CoroutineScope
是一种组织性的东西--它允许你将协程组合在一起,以强制执行structured concurrency.基本上,它允许您控制作用域中所有内容的生命周期(包括在其他协程中启动的协程),并处理传播结果和错误以及取消作用域中的所有内容等事情.More info here
所有协程构建器函数(包括launch
)都运行inside a CoroutineScope
(如果您想这样看的话,可以将其作为接收器运行on it):
fun CoroutineScope.launch(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit
): Job
因此,您示例中的launch
调用运行的是inside the current 102,这是由runBlocking
builder提供的:
expect fun <T> runBlocking(
context: CoroutineContext = EmptyCoroutineContext,
block: suspend CoroutineScope.() -> T
): T
看到你通过的Lambda实际上是CoroutineScope.() -> T
了吗?它以CoroutineScope
作为接收器运行--这就是你所说的launch
.你不能在任何地方呼叫它!
因此,当您在您的示例中创建CoroutineScope
时,您是在嵌套runBlocking
提供的inside这个CoroutineScope
.runBlocking
不允许它后面的其余代码继续(即,它blocks执行),直到它的CoroutineScope
中的所有内容都完成为止.在其中创建您自己的CoroutineScope
允许您定义一个您可以控制的协程子集--您可以控制cancel
个协程,但是如果还有其他协程在runBlocking
作用域中运行,它将一直阻塞,直到它们也完成为止.
就像Louis在另一个答案中所说的,您实际上并没有在您创建的作用域内创建任何协程.代码只是在runBlocking
开始运行您传递的代码块的协程中运行.看看这个:
fun main() {
println("Main")
runBlocking {
coroutineScope {
delay(1000)
println("I'm in a coroutine scope")
}
launch {
delay(500)
println("First new coroutine")
}
launch {
delay(50)
println("Second new coroutine")
}
}
}
Main
I'm in a coroutine scope
Second new coroutine
First new coroutine
单个协程程序中的代码是按顺序执行的-因此发生的情况是
- 你从Main开始
- 你进入
runBlocking
街区的协和程序
- 你创造了一个
CoroutineScope
,只影响你身上的launch
(等)物品
- 您延迟,然后打印一行
- 你打到了前
launch
个,然后创造了一个新的协和程序.这从延迟500毫秒开始,但现在它自己运行--不同的协程运行concurrently
- 你移到下一行,然后
launch
是第二条协议线.它也会自己运行,并且会立即延迟50毫秒.现在有3个协同 routine 在运行
- 您已经完成了块中的代码执行--这个协程已经完成了.However,有两个正在运行的协程也在这个
CoroutineScope
上启动,所以runBlocking
等待它们完成.
- 延迟最短的第二个协程程序首先打印,然后完成
- 第一个协程程序最后结束,因为即使它启动得更早,它们也都是独立运行的
- 现在
runBlocking
CoroutineScope
内部的一切都完成了,它可以完成并允许在main()
中执行
如果您在您创建的作用域中创建了一个协程,那么它的工作方式都是一样的--只是您可以对其中的东西进行细粒度的控制,并且您可以专门使用该嵌套作用域中的协程,而不会影响外部作用域中的内容.重要的是一旦内部作用域完成了,它就可以通知外部作用域一切都完成了,诸如此类的事情