如何从暂停功能启动协程并使其使用当前的作用域? (这样,直到启动的协程也结束,作用域才结束)
我想写类似下面的内容–
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.3
和cotlinx-coroutines-core:1.0.1
。
答案 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在上面发布了一个更好的解决方案。