如何使用当前父级Scope在“悬浮乐趣”中启动Kotlin协程?

时间:2018-12-20 05:24:25

标签: kotlin kotlinx.coroutines

如何从暂停功能启动协程并使其使用当前的作用域? (这样,直到启动的协程也结束,作用域才结束)

我想写类似下面的内容–

import kotlinx.coroutines.*

fun main() = runBlocking { // this: CoroutineScope
    go()
}

suspend fun go() {
    launch {
        println("go!")
    }
}

但是这有一个语法错误:“未解析的参考:启动”。看来launch必须以下列方式之一运行–

GlobalScope.launch {
    println("Go!")
}

runBlocking {
    launch {
        println("Go!")
    }
}

withContext(Dispatchers.Default) {
    launch {
        println("Go!")
    }
}

coroutineScope {
    launch {
        println("Go!")
    }
}

这些替代方法都无法满足我的需求。代码要么“阻塞”而不是“产生”,要么产生,但是父作用域不会在父作用域本身结束之前等待其完成。

我需要它在当前的父协程范围内“生成”(启动),并且该父级范围应等待所生成的协程完成后才能结束。

我希望launch中的一个简单suspend fun是有效的,并使用其父范围。

我正在使用Kotlin 1.3cotlinx-coroutines-core:1.0.1

2 个答案:

答案 0 :(得分:4)

您应该将函数go扩展为CoroutineScope

fun main() = runBlocking {
    go()
    go()
    go()
    println("End")
}

fun CoroutineScope.go() = launch {
    println("go!")
}

阅读此article可以理解为什么不创建一个新的suspend而不是从其他协程开始使用coroutineScope{}函数的好主意。

惯例是:如果需要启动并行协程,则在suspend函数中调用其他suspend函数并创建一个新的CoroutineScope。结果是,协程将仅在所有新启动的协程完成后才返回(结构化并发)。

另一方面,如果您需要在不知道范围的情况下启动新的协程,则可以创建CoroutineScope的扩展功能,而扩展功能本身不是suspendable。现在,调用者可以决定应使用哪个范围。

答案 1 :(得分:0)

我相信我找到了一个解决方案,即with(CoroutineScope(coroutineContext)。以下示例说明了这一点–

import kotlinx.coroutines.*

fun main() = runBlocking {
    go()
    go()
    go()
    println("End")
}

suspend fun go() {
//  GlobalScope.launch {                     // spawns, but doesn't use parent scope
//  runBlocking {                            // blocks
//  withContext(Dispatchers.Default) {       // blocks
//  coroutineScope {                         // blocks
    with(CoroutineScope(coroutineContext)) { // spawns and uses parent scope!
        launch {
            delay(2000L)
            println("Go!")
        }
    }
}

但是,Rene在上面发布了一个更好的解决方案。