You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin Channel无法正常结束:无需cancelChildren()如何实现自然终止?

Kotlin Channel produce扩展函数疑问:无需cancelChildren()如何让代码自然结束?

我是Kotlin Channel的新手,以下是使用produce扩展函数(返回ReceiveChannel)的练习代码。在repeat(10)的每次循环中,变量cur会被重新赋值为新的ReceiveChannel,因此我在filter扩展函数中调用了cancel()方法。

初始代码(未正常结束)

我原本期望代码能正常结束,但实际并未实现:

fun CoroutineScope.numbersFrom(start: Int) = produce<Int> {
    var x = start
    while (true) send(x++) // 无限发送从start开始的整数
}

fun CoroutineScope.filter(numbers: ReceiveChannel<Int>, prime: Int) = produce<Int> {
    for (x in numbers) if (x % prime != 0) send(x)
    numbers.cancel() // 在此处取消
}

fun main() {
    runBlocking {
        var cur = numbersFrom(2) // 无限发送数字...
        repeat(10) {
            val prime = cur.receive() // 只获取一个元素
            println(prime)
            cur = filter(cur, prime) // 新的接收通道
        }
        cur.cancel() // 在此处取消
    }
}

尝试修改后抛出异常

我尝试了以下代码,但运行时出现异常:

Exception in thread "main" kotlinx.coroutines.JobCancellationException: BlockingCoroutine was cancelled; job=BlockingCoroutine{Cancelled}@26a7b76d

代码如下:

fun CoroutineScope.numbersFrom(start: Int) = produce<Int> {
    var x = start
    while (true) send(x++) // 无限发送从start开始的整数
}

fun CoroutineScope.filter(numbers: ReceiveChannel<Int>, prime: Int) = produce<Int> {
    for (x in numbers) if (x % prime != 0) send(x)
    numbers.cancel()
}

fun main() {
    runBlocking {
        var cur = numbersFrom(2) // 无限发送数字...
        repeat(10) {
            val prime = cur.receive() // 只获取一个元素
            println(prime)
            cur = filter(cur, prime) // 新的接收通道
        }
        cur.cancel()
        coroutineContext.cancel()
    }
}

使用cancelChildren()可正常结束的代码

此外,以下代码通过取消所有子协程可以自然结束:

fun CoroutineScope.numbersFrom(start: Int) = produce<Int> {
    var x = start
    while (true) send(x++) // 无限发送从start开始的整数
}

fun CoroutineScope.filter(numbers: ReceiveChannel<Int>, prime: Int) = produce<Int> {
    for (x in numbers) if (x % prime != 0) send(x)
    numbers.cancel()
}

fun main() {
    runBlocking {
        var cur = numbersFrom(2) // 无限发送数字...
        repeat(10) {
            val prime = cur.receive() // 只获取一个元素
            println(prime)
            cur = filter(cur, prime) // 新的接收通道
        }
        coroutineContext.cancelChildren()
    }
}

请问有没有不使用coroutineContext.cancelChildren()就能让代码自然结束的方法?


内容的提问来源于stack exchange,提问作者Hyun

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 18:40:37