取消Kotlin中不可取消的协同路由
考虑这个名称所暗示的不可取消的协同程序取消Kotlin中不可取消的协同路由,kotlin,kotlin-coroutines,Kotlin,Kotlin Coroutines,考虑这个名称所暗示的不可取消的协同程序 fun main(args: Array<String>) = runBlocking { val nonCancellableJob = launch(Dispatchers.Default) { for (i in 1..1000) { if (i % 100 == 0) { println("Non cancellable iteration $i
fun main(args: Array<String>) = runBlocking {
val nonCancellableJob = launch(Dispatchers.Default) {
for (i in 1..1000) {
if (i % 100 == 0) {
println("Non cancellable iteration $i")
}
}
}
println("Cancelling non cancellable job...")
nonCancellableJob.cancelAndJoin()
}
fun main(args:Array)=运行阻塞{
val nonCancellableJob=launch(Dispatchers.Default){
对于(1..1000中的i){
如果(i%100==0){
println(“不可取消的迭代$i”)
}
}
}
println(“取消不可取消的作业…”)
nonCancellableJob.cancelAndJoin()
}
现在,如果我去掉显式dispatcher
Dispatchers.Default
并使用继承的dispatcher.Default,即launch{…}
,则协同程序将立即取消,而不打印任何内容。似乎正在取消一个非取消的协同程序!它是一个bug还是什么?继承的dispatcher运行在您启动它的同一个线程上。这使得runBlocking
建立了一个顶级循环,该循环遍历在其内部运行的协程,逐个恢复它们。在当前协同进程挂起之前,它无法恢复下一个协同进程
在您的代码中,顶级的
runBlocking
corroutine创建了一个子corroutine,然后在没有挂起的情况下,继续执行其他操作:打印消息并取消刚刚创建的corroutine。在这一点上,协同程序仍然处于已创建但未运行的边缘。您的cancelAndJoin
调用在此状态下取消它,直到它有机会永远占用runBlocking
调度程序。它立即将状态更改为“通过取消完成”,整个程序结束。继承的调度程序在启动它的同一线程上运行。这使得runBlocking
建立了一个顶级循环,该循环遍历在其内部运行的协程,逐个恢复它们。在当前协同进程挂起之前,它无法恢复下一个协同进程
在您的代码中,顶级的
runBlocking
corroutine创建了一个子corroutine,然后在没有挂起的情况下,继续执行其他操作:打印消息并取消刚刚创建的corroutine。在这一点上,协同程序仍然处于已创建但未运行的边缘。您的cancelAndJoin
调用在此状态下取消它,直到它有机会永远占用runBlocking
调度程序。它立即将状态更改为“通过取消完成”,整个程序结束。当您不使用调度程序时。默认情况下,启动
将继承运行阻塞
的调度程序,这似乎会将执行推迟到需要时
即使您的协同程序在运行时无法取消(因为它没有任何活动检查,也没有挂起点),但仍然可以在开始执行之前取消它
您可以修改launch builder的属性以更改此行为:
要在声明时立即执行它,请执行以下操作:
val nonCancellableJob = launch(start = CoroutineStart.UNDISPATCHED) { ... }
要防止在开始前取消,请执行以下操作:
val nonCancellableJob = launch(start = CoroutineStart.ATOMIC) { ... }
当您不使用调度程序时。默认值
则launch
继承了runBlocking
的调度程序,它似乎将执行推迟到需要时
即使您的协同程序在运行时无法取消(因为它没有任何活动检查,也没有挂起点),但仍然可以在开始执行之前取消它
您可以修改launch builder的属性以更改此行为:
要在声明时立即执行它,请执行以下操作:
val nonCancellableJob = launch(start = CoroutineStart.UNDISPATCHED) { ... }
要防止在开始前取消,请执行以下操作:
val nonCancellableJob = launch(start = CoroutineStart.ATOMIC) { ... }
谢谢这是否意味着理论上有可能在不修改上下文的start
元素的情况下启动和执行协同程序,实际上,runBlocking
的调度程序在到达主runBlocking
块中的挂起点之前不会执行您的launch
。是的,我知道了。在println
前面添加delay(10)
,强制runBlocking
调度程序启动并执行协同程序。再次感谢,谢谢。这是否意味着理论上有可能在不修改上下文的start
元素的情况下启动和执行协同程序,实际上,runBlocking
的调度程序在到达主runBlocking
块中的挂起点之前不会执行您的launch
。是的,我知道了。在println
前面添加delay(10)
,强制runBlocking
调度程序启动并执行协同程序。再次感谢。