在挂起的函数中调用协程构建器(启动、异步)时,coroutineContext 不明确

Ambiguous coroutineContext while calling co-routine builders (launch, async) in a suspended function

我有一个 class Runner 实现了 CoroutineScope 接口,如下所示。它有一个名为 run 的挂起函数。当我在这个暂停的 run 函数中使用协同例程构建器函数 (launch, async) 时,我收到以下警告

Ambiguous coroutineContext due to CoroutineScope receiver of suspend function

Runner class 实现了一个 coroutineContext 属性。有人可以解释警告消息背后的逻辑吗?

class Runner: CoroutineScope {

    override private val coroutineContext = Dispatchers.IO

    suspend fun run()  {
           val job1 = launch { delay(2000); println("launching job1") }
           val job2 = launch { delay(2000); println("launching job2") }
           listOf(job1, job2).forEach { it.join() }
    }

}

尽量避免在 Coroutine Scoped class 或函数内挂起函数 除非它会抛出上述警告

class Runner: CoroutineScope {

            override private val coroutineContext = Dispatchers.IO

            suspend fun run()  {
                   val job1 = launch { delay(2000); println("launching job1") }
                   val job2 = launch { delay(2000); println("launching job2") }
                   listOf(job1, job2).forEach { it.join() }
            }

        }

class Runner: CoroutineScope {
            //also remove the `private` visibility modifier
            override val coroutineContext = Dispatchers.IO

            fun run()  {
                   val job1 = launch { delay(2000); println("launching job1") }
                   val job2 = launch { delay(2000); println("launching job2") }
                   this.launch{
                       listOf(job1, job2).forEach { it.join() }
                   }   
            }

        }

由于 suspend 修饰符,它是模棱两可的。您的 run() 函数将从另一个 couroutineScope 调用。所以它里面的 launch 构建器可以启动协程或在现有协程内挂起。这就是歧义。您可以通过删除挂起修饰符来修复它:

class Runner : CoroutineScope {

    override val coroutineContext = Dispatchers.IO

    fun run() = launch {
            val job1 = launch { delay(2000); println("launching job1") }
            val job2 = launch { delay(2000); println("launching job2") }
            listOf(job1, job2).forEach { it.join() }
        }

}

您需要明确声明run()使用 Runner 的 coroutineContext,这将消除歧义

suspend fun run() = withContext(coroutineContext) {
    val job1 = launch { delay(2000); println("launching job1") }
    val job2 = launch { delay(2000); println("launching job2") }
    listOf(job1, job2).forEach { it.join() }
}

或者,如果您添加一个参数,您可以使用调用 运行 的上下文,例如

suspend fun run(cc:CoroutineContext = coroutineContext) = withContext(cc) {
    val job1 = launch { delay(2000); println("launching job1") }
    val job2 = launch { delay(2000); println("launching job2") }
    listOf(job1, job2).forEach { it.join() }
}