android - 在 Kotlin 协程中指定调度程序/上下文有多重要?如果你不指定它们会发生什么?

标签 android kotlin-coroutines

如果启动协程但未指定调度程序(例如 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 .
    如果范围是 lifecycleScopeviewModelScope由 Android 提供,那么协程将使用 Dispatchers.Main.immediate默认。
    如果使用 CoroutineScope() 创建范围没有特定调度程序的工厂函数,Dispatchers.Default将被使用(见 the "Custom usage" section in the documentation )。
    如果使用 MainScope() 创建范围如果没有特定的调度程序,它将使用 Dispatchers.Main根据 the same documentation .
    如果范围由 runBlocking 提供, 然后它将使用一个特殊的调度程序,它像一个事件循环一样工作,并在调用 runBlocking 的线程中执行你的协程。 (这很好,因为无论如何该线程都会被阻止)。
    如果范围由另一个(外部)协程构建器提供,例如 launchasync (这意味着您的协程是该协程的子协程),那么调度程序将从用于启动父协程的范围中获取,除非它们覆盖它。因此,您可以一直向上,直到达到上述选项之一:
    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/

    相关文章:

    android - 如何恢复协程的真实调用轨迹?

    android - 浏览多个 Activity

    android - 从非生命周期类的主调度程序切换到 IO 调度程序

    android - 创建新 View 时动态隐藏 View stub

    Android 4.0 自定义通知像谷歌音乐

    kotlin - Job 作为 CoroutineScope 和 launch 的参数有什么不同?

    exception - Kotlin协程异常处理——如何抽象try-catch

    kotlin - 异常后如何恢复流程

    java - ListPreference标记导致我的应用崩溃

    java - 如何从 Firebase 数据库检索多个数据?