0

采取以下程序:

package example

import kotlinx.coroutines.InternalCoroutinesApi
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.selects.select

@InternalCoroutinesApi
fun main() {
    runBlocking {
        val chan = Channel<Unit>()
        chan.close()
        select<Unit> {
            println("Register onReceiveOrClosed.")
            chan.onReceiveOrClosed {
                println("Selected value $it.")
            }
        }
        println("Done.")
    }
}

运行它会给出以下输出:

Register onReceiveOrClosed.
Selected value Closed(null).
Selected value Closed(null).
Exception in thread "main" java.lang.IllegalStateException: Already resumed
    at kotlinx.coroutines.selects.SelectBuilderImpl.resumeWith(Select.kt:458)
    at kotlinx.coroutines.selects.SelectBuilderImpl.handleBuilderException(Select.kt:309)
    at example.ExampleKt$main$1.invokeSuspend(example.kt:28)
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
    at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:241)
    at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:270)
    at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:79)
    at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:54)
    at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
    at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:36)
    at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source)
    at example.ExampleKt.main(example.kt:10)
    at example.ExampleKt.main(example.kt)

我希望只看到一行,并且我希望不会看到任何异常(但当然,鉴于给定的块被执行两次Selected value Closed(null),异常是有意义的)。onReceiveOrClosed

我的理解onReceiveOrClosed不正确还是这是一个错误onReceiveOrClosed

我正在使用 Kotlin 1.3.50 和kotlinx-coroutines-core:1.3.1. 完整示例可在此处获得:https ://github.com/frececroka/kotlin-select-onreceiveorclosed 。

4

1 回答 1

0

我认为这是因为当您调用select该频道时,该频道已经关闭。如果您添加一些延迟,它将正常工作:

@InternalCoroutinesApi
fun main() {
    runBlocking {
        val chan = Channel<Unit>()
        launch {
            chan.close()
        }
        select<Unit> {
            println("Register onReceiveOrClosed.")
            chan.onReceiveOrClosed {
                println("Selected value $it.")
            }
        }
        println("Done.")
    }
}

// prints
// Register onReceiveOrClosed.
// Selected value Closed(null).
// Done.

我不确定这是错误还是预期行为

于 2019-09-12T13:02:52.997 回答