gpt4 book ai didi

kotlin - 为什么延迟会使 co 例程可以取消

转载 作者:行者123 更新时间:2023-12-01 23:35:44 25 4
gpt4 key购买 nike

fun main() = runBlocking {

var i = 1

var job = launch (Dispatchers.Default){

println("Thread name = ${Thread.currentThread().name}")
while (i < 10) { // replace i < 10 to isActive to make coroutine cancellable
delay(500L)
// runBlocking { delay(500L) }
println("$isActive ${i++}")
}
}

println("Thread name = ${Thread.currentThread().name}")
delay(2000L) // delay a bit
println("main: I'm tired of waiting!")
job.cancelAndJoin() // cancels the job and waits for its completion
println("main: Now I can quit.")

}

output

Thread name  =  main
Thread name = DefaultDispatcher-worker-1
true 1
true 2
true 3
main: I'm tired of waiting!
main: Now I can quit.

如果我使用runBlocking {delay(500L)}那么上面的协同例程是不可取消的。因此,它将打印 9 之前的所有值。

但是当我自动使用delay(500L)时,协同例程可以被取消。为什么?

最佳答案

delay 实际上本身并没有做任何事情,它只是 schedules the coroutine to be resumeda later point in time 。当然,延续可以是 cancelled随时。

另一方面,

runBlocking 实际上会阻塞一个线程(这就是为什么编译器会提示协程内的阻塞操作,以及为什么你不应该永远使用runBlocking 在单元测试之外)。

注意:由于 main 现在可以是一个挂起函数,因此通常不需要在核心应用程序代码中使用它。

This function should not be used from a coroutine
runBlocking

协程与线程一样,并不是真正可中断的;他们必须依赖合作取消(另请参阅原因 stopping threads is bad )。这意味着取消实际上也不会执行任何操作;当您取消上下文时,它只是通知其所有子上下文自行取消,但任何仍在运行的代码将继续运行,直到达到取消检查为止。

重要的是要认识到runBlocking 不是一个挂起函数。它无法暂停、恢复或取消。默认情况下,父上下文不会传递给它(它接收 EmptyCoroutineContext ),因此用于执行 runBlocking 的协程不会对上游发生的任何事情使用react。

当你写的时候

while (i < 10) {
runBlocking { delay(500L) }
println("$isActive ${i++}")
}

此处没有可取消的操作。因此,代码从不检查其上下文是否已被取消,因此它将继续执行直到完成。

延迟,但是,is cancellable ;一旦其父上下文被取消,它会立即恢复并抛出异常(即停止。)

看一下生成的代码:

@Nullable
public final Object invokeSuspend(@NotNull Object $result) {
switch (this.label) {
case 0:
while (i.element < 10) {
BuildersKt.runBlocking$default( ... );
...
System.out.println(var3);
}

return Unit.INSTANCE;
default:
throw new IllegalStateException( ... );
}
}

对比一下

while (i.element < 10) {
BuildersKt.runBlocking$default( ... );
...
System.out.println(var3);
}

do {
...
System.out.println(var3);
if (i.element >= 10) {
return Unit.INSTANCE;
}
...
} while (DelayKt.delay(500L, this) != var5);

为简洁起见,省略了变量声明和参数 (...)。

<小时/>如果当前线程是 interrupted

runBlocking 将提前终止,但这又是完全相同的协作机制,只不过它在线程级别而不是协程上运行。

关于kotlin - 为什么延迟会使 co 例程可以取消,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61556631/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com