在 Android 中使用 Dispatcher v/s 主线程会发生啥

Posted

技术标签:

【中文标题】在 Android 中使用 Dispatcher v/s 主线程会发生啥【英文标题】:What happens using a Dispatcher v/s Main Thread in Android在 Android 中使用 Dispatcher v/s 主线程会发生什么 【发布时间】:2022-01-12 16:23:52 【问题描述】:

android 的上下文中,调度程序与主线程有什么区别。

根据我对文档的理解,

它由 JVM 上的共享线程池提供支持。默认情况下, 此调度程序使用的最大并行度等于 CPU 核心数,但至少为两个。并行度 X 保证在此期间最多可以执行 X 个任务 并行调度程序。

它会产生一个新线程,还是会根据日志名称DefaultDispatcher-worker-1 有一个工作线程,该工作线程将与除主线程之外的线程池进行通信以处理协同程序块或工作线程本身是一个 Co-例行公事?

override fun onCreate(savedInstanceState: Bundle?) 
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val timeInMillis = measureTimeMillis 
            GlobalScope.launch(Dispatchers.Default) 
                Log.d(TAG, "Starting coroutine in thread $Thread.currentThread().name")
                val answer = doNetworkCall()
                withContext(Dispatchers.Main) 
                    Log.d(TAG, "Setting text in thread $Thread.currentThread().name")
                
            

        
        Log.d(TAG, "(The operation took $timeInMillis ms)")

    

【问题讨论】:

【参考方案1】:

Dispatcher 本质上是一个线程池。使用launch(Dispatchers.Default)时,协程中用于运行代码的Thread将从Dispatchers.Default获取。每次在协程中调用挂起函数时,当协程在该调用后恢复时,它可能会在来自同一 Dispatchers.Default 线程池的不同 Thread 实例上恢复。

"DefaultDispatcher-worker-1" 是来自Dispatcher.Default 池的文字Thread 实例的名称。

withContext 本身是一个挂起函数调用,因此withContext 块之后的任何代码也将在来自Dispatchers.Default 的某个线程上恢复。 (您的示例中没有)。

withContext(Dispatchers.Main) 中的代码将在来自Dispatchers.Main 的线程上运行。

Dispatchers.Main 是一个特殊的 Dispatcher,它只有一个线程,并且该线程与操作系统使用的主线程相同。

您应该很少需要使用 GlobalScope 并且不鼓励使用它,因为它不允许轻松管理协程生命周期。如果你改用lifecycleScope,你的协程会在关联的Activity或Fragment关闭时自动取消。这通常是您想要的,因为 Activity 或 Fragment 在它消失后不应该继续工作。

通常在 Android 上,大多数协程应该从 lifecycleScopeviewModelScope 启动,并且不需要指定 Dispatcher,因为这些范围默认使用 Dispatchers.Main,这通常是您想要的。 (实际上,他们使用了一个名为Dispatchers.Main.immediate 的不同调度程序,它也使用主线程,但也可以立即运行协程的第一部分,而无需推迟到主线程循环的下一帧。你不需要担心区别。)您可以将需要其他调度程序的协程部分包装在 withContext 中。如果您只调用挂起函数,则不需要这样做。按照惯例,如果需要,可以暂停功能以在内部委托给特定的 Dispatcher。

如果您在viewModelScope 中启动一个协程,该协程执行一些阻塞工作并且从不接触任何仅主线程的东西,则上述段落的一个例外可能是。然后您可以跳过withContext 并使用launch 显式指定调度程序。

【讨论】:

只是一个小细节,但视图模型和生命周期范围实际上由 Dispatchers.Main.immediate 支持,作为一种额外优化的手段。 没错,说他们使用 Main 是不准确的,但这对新手来说有点混乱。我会尽力澄清。 很好,很好的解释。您能否帮我提供任何链接,以提供协程与线程池的行为方式的可视化? 我不知道有任何图表或文章详细说明了它的工作原理。我了解池如何工作的基本概念,并且我没有费心去找出协程背后使用的确切机制。

以上是关于在 Android 中使用 Dispatcher v/s 主线程会发生啥的主要内容,如果未能解决你的问题,请参考以下文章

一起了解Android开源框架&&解析okhttp框架任务核心类dispatcher

Android Firebase Job Dispatcher 会通过更改日期时间触发吗?

10.6 android输入系统_Dispatcher线程_总体框架

Android OkHttp3 :最简单&粗暴(使用与原理)讲解

何时在 React 应用程序中使用 Dispatcher

Android Dagger2,Singleton交叉组件