Kotlin不同作用域下协程执行顺序差异原因咨询
Kotlin协程执行顺序差异的原因解析
核心差异源于单线程调度器下的协程调度顺序,结合coroutineScope的挂起等待特性和launch的非阻塞调度特性,我们可以拆解两个场景的执行流程:
前提说明
runBlocking默认使用单线程调度器,所有协程任务都在同一个线程上执行,调度器会按任务加入队列的先后顺序处理可执行的协程。
结果A的执行流程
- 第一个
coroutineScope:内部无launch,所有代码都是同步执行的挂起逻辑,直接顺序输出:in the coroutineScope 1 coroutineScope inside the coroutineScope1 - 第二个
coroutineScope:- 先执行同步代码
println("in the coroutineScope 2"),输出该行。 - 调用
launch,将该协程任务加入调度队列。 coroutineScope挂起,等待所有子协程完成。此时调度器无其他待处理任务,立即执行刚加入的launch协程:- 打印
coroutine in the coroutineScope 2 - 内部嵌套的
coroutineScope同步执行,打印coroutineScope inside the coroutineScope2 coroutine
- 打印
- 子协程全部完成,
coroutineScope恢复,退出该作用域。
- 先执行同步代码
- 回到
runBlocking主协程:- 调用
launch { // #1 },将该协程加入调度队列。 - 执行同步代码
println("in the blocking"),输出该行。 runBlocking等待所有子协程完成,调度器执行队列中的#1协程,打印coroutine in the blocking。
- 调用
结果B的执行流程
- 第一个
coroutineScope:和结果A完全一致,输出相同内容。 - 回到
runBlocking主协程:- 调用
launch { // #1 },将该协程加入调度队列。
- 调用
- 第二个
coroutineScope:- 先执行同步代码
println("in the coroutineScope 2"),输出该行。 - 调用
launch,将该协程任务加入调度队列(此时队列中已有#1的协程任务)。 coroutineScope挂起等待子协程完成,调度器按队列顺序处理任务:- 先执行队列中的#1协程,打印
coroutine in the blocking - 再执行第二个
coroutineScope内的launch协程,依次输出coroutine in the coroutineScope 2和coroutineScope inside the coroutineScope2 coroutine
- 先执行队列中的#1协程,打印
- 子协程全部完成,
coroutineScope恢复,退出该作用域。
- 先执行同步代码
- 回到
runBlocking主协程:执行同步代码println("in the blocking"),输出该行。
关键结论
launch的作用是将协程任务加入调度队列,不会立即执行,具体执行时机由调度器决定。coroutineScope会挂起当前协程,直到所有子协程完成,此时调度器会处理队列中等待的所有协程任务。- 单线程调度器下,协程任务严格按加入队列的先后顺序执行,这就是调整
launch位置导致输出顺序变化的根本原因。
内容的提问来源于stack exchange,提问作者Steven shih
相关产品推荐
相关产品推荐

