android - 协程的执行顺序是什么?
问题描述
考虑 kotlin 中的以下代码。
val scope = CoroutineScope(Dispatchers.Main + Job())
scope.launch {
println("inside coroutine")
}
println("outside coroutine")
我们在 Main(UI) 线程中创建了一个协程,协程之后有一些代码。
我知道在实际代码中这样做没有多大意义,但这只是一个理论问题。
考虑到协程在主线程中运行,为什么println("outside coroutine")总是先执行?
我本以为有时我会先在 coroutine 之外看到,而在其他时候,首先在 coroutine 内部,有点像两个线程。
谁(OS 或 Coroutines 实现)决定先运行协程之外的 coe?
解决方案
考虑到协程在主线程中运行,为什么 println("outside coroutine") 总是先执行?
让我们想象一下,您的代码是这样的:
someView.post {
println("inside post")
}
println("outside post")
在这里,我们创建一个Runnable
(lambda 表达式) 并将其传递给post()
some View
。post()
说这Runnable
将run()
在主应用程序线程上......最终。这Runnable
被放在Looper
主应用程序线程使用的工作队列中,当它Runnable
到达队列的顶部时它会被执行(或多或少 - 细节是更混乱的 IIRC,但在这里并不重要)。
但是如果您在主应用程序线程上执行此代码,println("outside post")
将始终首先打印。被Runnable
放置到队列中以便稍后执行,但您仍在主应用程序线程上执行,因此即使队列为空,Runnable
在您将主应用程序线程的控制权返回给 Android 之前,它也不会运行。因此,在调用 之后post()
,继续执行println("outside post")
。
在幕后,Dispatchers.Main
基本上是在使用post()
(同样,细节更复杂,但对于这个讨论来说不是太重要)。因此,当您launch()
使用协程时,该 lambda 表达式会排队等待最终在主应用程序上执行。但是,您已经在主应用程序线程上,因此执行正常继续,并且println("outside post")
在协程有机会做任何事情之前被打印出来。
假设您的代码改为:
val scope = CoroutineScope(Dispatchers.Main + Job())
scope.launch {
println("inside coroutine")
}
scope.launch {
println("inside another coroutine")
}
现在您处于理论上可以先打印这些行中的任何一行的情况。您正在排队两个 lambda 表达式,由调度程序决定在什么时候在哪个线程上运行什么。在实践中,如果总是首先打印“内部协程”,我不会感到惊讶,因为一个简单的实现Dispatchers.Main
将在没有其他约束的情况下使用 FIFO 排序(例如,协程在 I/O 上被阻塞)。但是,您不应该假设这两个协程的特定调用顺序。
推荐阅读
- ztree - 加载参数表
- python - 如何遍历字符串中的所有重叠匹配?
- azure - 需要帮助调查 Azure App Service .NET Core 2.1 ArgumentOutOfRangeException 和 System.OverflowException
- java - ActionBar内的后退按钮如何完成当前活动
- java - 如何将常量字段导出到 swagger ui?
- kubernetes - Kubernetes 命名空间中密码安全的重要性?
- ffmpeg - ffmpeg 将视频分割成 hls 切片,为什么 hls_time 选项不起作用?
- javascript - 对象可能是“null”——TypeScript linter 出错
- reactjs - 在 npm 开始 npm 错误!可以在以下位置找到此运行的完整日志:
- python - 我应该从“urllib.request.urlretrieve(..)”切换到“urllib.request.urlopen(..)”吗?