如何在使用当前父范围的“暂停乐趣”中启动 Kotlin 协程?
How to launch a Kotlin coroutine in a `suspend fun` that uses the current parent Scope?
如何从挂起函数启动协程并让它使用当前作用域? (这样 Scope 在启动的协程也结束之前不会结束)
我想写类似下面的东西 –
import kotlinx.coroutines.*
fun main() = runBlocking { // this: CoroutineScope
go()
}
suspend fun go() {
launch {
println("go!")
}
}
但这有一个语法错误:"Unresolved Reference: launch"。看起来 launch
必须是 运行 以下列方式之一 –
GlobalScope.launch {
println("Go!")
}
或
runBlocking {
launch {
println("Go!")
}
}
或
withContext(Dispatchers.Default) {
launch {
println("Go!")
}
}
或
coroutineScope {
launch {
println("Go!")
}
}
None 这些替代方案可以满足我的需要。代码 "blocks" 而不是 "spawning",或者它产生但父作用域不会在父作用域本身结束之前等待它完成。
我需要它 "spawn" 在当前的父协程作用域中启动(启动),并且该父作用域应该等待生成的协程在它自己结束之前完成。
我预计 suspend fun
中的简单 launch
将有效并使用其父范围。
我正在使用 Kotlin 1.3
和 cotlinx-coroutines-core:1.0.1
。
我相信我找到了解决方案,那就是 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 在上面发布了一个更好的解决方案。
您应该使函数 go
成为 CoroutineScope
的扩展函数:
fun main() = runBlocking {
go()
go()
go()
println("End")
}
fun CoroutineScope.go() = launch {
println("go!")
}
阅读此 article 了解为什么在 suspend
函数中启动其他协程而不创建新的 coroutineScope{}
.
不是一个好主意
惯例是:在一个suspend
函数中调用其他suspend
函数并创建一个新的CoroutineScope
,如果你需要启动并行协程。结果是,当所有新启动的协程都完成(结构化并发)时,协程只会 return。
另一方面,如果您需要在不知道作用域的情况下启动新协程,您可以创建一个 CoroutineScope
的扩展函数,它本身不是 suspendable
。现在调用者可以决定应该使用哪个范围。
假设您正在处理一些 RxJava Observable,现在不是重构它们的时候,您现在可以通过这种方式获取挂起函数的 CoroutineScope:
suspend fun yourExtraordinarySuspendFunction() = coroutineScope {
val innerScope = this // i.e. coroutineScope
legacyRxJavaUggh.subscribe { somePayloadFromRxJava ->
innerScope.launch {
// TODO your extraordinary work
}
}
}
如何从挂起函数启动协程并让它使用当前作用域? (这样 Scope 在启动的协程也结束之前不会结束)
我想写类似下面的东西 –
import kotlinx.coroutines.*
fun main() = runBlocking { // this: CoroutineScope
go()
}
suspend fun go() {
launch {
println("go!")
}
}
但这有一个语法错误:"Unresolved Reference: launch"。看起来 launch
必须是 运行 以下列方式之一 –
GlobalScope.launch {
println("Go!")
}
或
runBlocking {
launch {
println("Go!")
}
}
或
withContext(Dispatchers.Default) {
launch {
println("Go!")
}
}
或
coroutineScope {
launch {
println("Go!")
}
}
None 这些替代方案可以满足我的需要。代码 "blocks" 而不是 "spawning",或者它产生但父作用域不会在父作用域本身结束之前等待它完成。
我需要它 "spawn" 在当前的父协程作用域中启动(启动),并且该父作用域应该等待生成的协程在它自己结束之前完成。
我预计 suspend fun
中的简单 launch
将有效并使用其父范围。
我正在使用 Kotlin 1.3
和 cotlinx-coroutines-core:1.0.1
。
我相信我找到了解决方案,那就是 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 在上面发布了一个更好的解决方案。
您应该使函数 go
成为 CoroutineScope
的扩展函数:
fun main() = runBlocking {
go()
go()
go()
println("End")
}
fun CoroutineScope.go() = launch {
println("go!")
}
阅读此 article 了解为什么在 suspend
函数中启动其他协程而不创建新的 coroutineScope{}
.
惯例是:在一个suspend
函数中调用其他suspend
函数并创建一个新的CoroutineScope
,如果你需要启动并行协程。结果是,当所有新启动的协程都完成(结构化并发)时,协程只会 return。
另一方面,如果您需要在不知道作用域的情况下启动新协程,您可以创建一个 CoroutineScope
的扩展函数,它本身不是 suspendable
。现在调用者可以决定应该使用哪个范围。
假设您正在处理一些 RxJava Observable,现在不是重构它们的时候,您现在可以通过这种方式获取挂起函数的 CoroutineScope:
suspend fun yourExtraordinarySuspendFunction() = coroutineScope {
val innerScope = this // i.e. coroutineScope
legacyRxJavaUggh.subscribe { somePayloadFromRxJava ->
innerScope.launch {
// TODO your extraordinary work
}
}
}