如果启动协程但未指定调度程序(例如 GlobalScope.launch {}
),使用什么调度程序?
如果该协程在主线程中启动,它会使用Dispatchers.main
吗? ?
另外,如果您没有在协程中指定调度程序或上下文会发生什么?假设您进行了数据库操作,但没有指定 Dispatchers.IO
任何地方。这会导致任何重大问题吗?
最佳答案
If a coroutine was launched and no dispatcher was specified (eg. GlobalScope.launch {}), what dispatcher is used?
如果协程构建器中没有指定调度器,则从
CoroutineScope
中的任意一个获取调度器。您正在启动您的协程。如果该范围的上下文中没有调度程序,则协程将使用 Dispatchers.Default
(例如,参见 launch 的文档)。请注意,范围是协程构建器调用的接收者:
GlobalScope.launch { ... }
然后 GlobalScope
是范围scope.launch { ... }
,看那个scope
launch { .. }
在野外,CoroutineScope
的一些实例必须以 this
的形式提供在那段代码中,这就是父作用域(有关它可能来自何处的示例,请参见下面的示例)以下是有关最常见协程作用域中使用的调度程序的一些信息:
如果范围是
GlobalScope
,则它没有任何调度程序,因此如前所述协程将使用 Dispatchers.Default
.如果范围是
lifecycleScope
或 viewModelScope
由 Android 提供,那么协程将使用 Dispatchers.Main.immediate
默认。如果使用
CoroutineScope()
创建范围没有特定调度程序的工厂函数,Dispatchers.Default
将被使用(见 the "Custom usage" section in the documentation )。如果使用
MainScope()
创建范围如果没有特定的调度程序,它将使用 Dispatchers.Main
根据 the same documentation .如果范围由
runBlocking
提供, 然后它将使用一个特殊的调度程序,它像一个事件循环一样工作,并在调用 runBlocking
的线程中执行你的协程。 (这很好,因为无论如何该线程都会被阻止)。如果范围由另一个(外部)协程构建器提供,例如
launch
或 async
(这意味着您的协程是该协程的子协程),那么调度程序将从用于启动父协程的范围中获取,除非它们覆盖它。因此,您可以一直向上,直到达到上述选项之一:parentScope.launch {
// here, this = child scope that gets the dispatcher from parentScope
launch {
// inherits from parent launch
}
launch(Dispatchers.IO) {
// here, this = child scope with overridden dispatcher
launch {
// inherits Dispatchers.IO from parent launch's scope
}
}
}
If that coroutine was launched in the main thread, would it use Dispatchers.main?
您可能可以将其与上一段拼凑起来,但只是重申一下:这取决于您启动协程的范围。
如果您从
lifecycleScope
启动协程/viewModelScope
,然后是的,它将在主线程上运行(在 Dispatchers.Main.immediate
中)。如果您调用
runBlocking
从主线程,那么它也会在主线程上运行协程(但不在 Dispatchers.Main
中),但你绝对不应该在 Android 中这样做。如果你使用类似
MainScope()
它确实会在 Dispatcher.Main
中运行.但在其他情况下,它很有可能在
Dispatchers.Default
上运行。 - 检查范围!Also, what happens if you do not specify dispatchers or context in your coroutines? Say you did database operations, but didn't specify
Dispatchers.IO
anywhere. Would that cause any major issues?
正如您从这个答案的开头所看到的,使用的调度程序取决于您的协程是如何启动的。如果我们假设您没有在任何地方指定任何调度程序,那么您的协程很有可能在
Dispatchers.Main
上运行。 (在 Android 中)或 Dispatchers.Default
.Dispatchers.Main
对 IO 的东西来说真的很糟糕,因为它会在 IO 发生时卡住你的 UI。我相信如果你在这个调度程序中运行错误的东西,Android 可能会崩溃,但我有一段时间没有做过 Android 开发,所以我不能肯定。Dispatchers.Default
是一个共享线程池,其大小取决于执行代码的机器的内核数量,因此它适用于 CPU 密集型任务。如果您在此调度程序中启动一堆执行阻塞 IO 的协程,您可能会阻塞所有线程并阻止其他协程运行,这确实不理想 - 它可能会导致延迟或缓慢,尤其是在您非常依赖协程的情况下。Dispatchers.IO
这并不神奇,但如果太多线程被阻塞,它会根据需要生成更多线程,以便其他协程可以运行。您仍然会产生额外线程的额外内存,但是当一些线程在 IO 上被阻塞时,其他协程将可以自由运行。您可以阅读更多关于如何使用调度程序 in the documentation .
关于android - 在 Kotlin 协程中指定调度程序/上下文有多重要?如果你不指定它们会发生什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69853525/