You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Kotlin协程未在挂起点(delay)处停止?

问题解析:协程取消未生效的原因

你遇到的问题核心在于**withContext切换到的上下文拥有独立的Job,不受原协程Job取消的影响**,且协程取消仅在挂起点才会触发终止。

代码行为拆解

  1. Job的独立性:

    • scope1的Job是parentJob1,job1是它的子Job;scope2的Job是parentJob2,和parentJob1完全独立,没有父子关联。
    • 当你调用job1.cancel()或parentJob1.cancel()时,只会取消job1及其关联的子Job,但withContext(scope2.coroutineContext)块内的协程绑定的是parentJob2,这个Job并未被取消,所以该块内的代码会完整执行——包括delay(1000)之后的打印语句。
  2. 协程取消的响应时机:

    • 协程被取消后,并不会立即终止,只有当它遇到挂起点(比如delay、yield等)时,才会抛出CancellationException并终止执行。
    • 在你的代码中,withContext块执行完毕后,回到job1的协程逻辑,此时job1已经被取消,但后续代码println("Coroutine in scope1 terminated")没有挂起点,所以会直接执行完成,不会触发取消终止。

对应你的观察点

  • (i) 调用parentJob1.cancel()行为一致:因为parentJob1是job1的父Job,取消父Job会递归取消所有子Job,但scope2的Job和它无关联,所以withContext块内的代码依然不受影响,执行流程和之前一致。
  • (ii) 加挂起点后协程停止:如果在withContext块后添加挂起点(比如delay(100)),那么job1的协程执行到这个挂起点时,会检测到自身已被取消,抛出CancellationException,后续的打印语句就不会执行了。

验证修改示例

如果要让withContext块内的代码也响应job1的取消,可以将scope2的Job设置为job1的子Job,比如:

val scope2 = CoroutineScope(parentJob2 + job1) // 将job1加入scope2的上下文

这样当job1被取消时,scope2的协程也会被取消,delay(1000)会触发终止,后续打印不会执行。

内容的提问来源于stack exchange,提问作者excitedGoose

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 04:48:21