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

Kotlin协程中CoroutineScope.launch与内部launch调用的差异解析

关于Kotlin结构化并发中两种launch调用的差异解析

问题背景

在学习Kotlin结构化并发时,以下两段代码的执行结果差异引发疑惑:

代码示例1:内部使用scope.launch

fun main(): Unit = runBlocking {
    other(this)
}

suspend fun other(scope: CoroutineScope) {
    val job = scope.launch {
        scope.launch {
            delay(200)
            println("e")
        }
        println("a")
    }
    job.invokeOnCompletion {
        println("Complete")
    }
}

输出结果:

a
Complete
e

代码示例2:内部使用launch

fun main(): Unit = runBlocking {
    other(this)
}

suspend fun other(scope: CoroutineScope) {
    val job = scope.launch {
       launch {
            delay(200)
            println("e")
        }
        println("a")
    }
    job.invokeOnCompletion {
        println("Complete")
    }
}

输出结果:

a
e
Complete

第一种情况中父Job在子Job完成前就结束,不符合结构化并发预期。原本以为scope.launch等价于内部的launch(即this.launch),但实际结果不同,需要明确两种调用的差异及原因。

差异解析

1. 第一种情况非结构化并发的原因

当在scope.launch的协程体内部再次调用scope.launch时,新创建的协程直接挂载到传入的外部scope(即runBlocking的根scope),而非外层job的子协程。

外层job执行完println("a")后就会进入完成状态,触发invokeOnCompletion打印Complete;而内部的scope.launch协程属于根scope的子协程,会继续运行,延迟200ms后打印e。此时外层job已经完成,因此出现a→Complete→e的顺序,这违背了结构化并发中“父协程等待所有子协程完成再结束”的规则。

2. 两种launch调用的核心差异

  • scope.launch(外部传入的scope):新协程的父Job是外部scope的根Job,与外层job是平级关系,不属于结构化并发的父子协程体系。外层job不会等待这个平级协程完成,因此自身可以提前结束。
  • launch(协程体内部的默认调用):协程体内部的launch等价于this.launch,这里的this是外层scope.launch创建的当前协程的CoroutineScope。新协程的父Job是外层的job,属于结构化并发的子协程。根据规则,父协程必须等待所有子协程完成后才会进入完成状态,因此外层job会等待内部协程打印e后,才触发invokeOnCompletion打印Complete,符合结构化并发预期。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 06:55:55