Dispatcher IO 的用法和 Default 的区别

Can*_*ato 31 kotlin kotlin-coroutines

在这个问题中:Kotlin Coroutines 选择 Dispatcher 我们可以理解Dispatcher.Default在 CPU 进程上使用,例如图像/视频转换以及Dispatcher.IO在写入/读取文件或 API 连接时。

但是在类Dispatcher.kt文档中,IO您会发现:

* This dispatcher shares threads with a [Default][Dispatchers.Default] dispatcher, so using
* `withContext(Dispatchers.IO) { ... }` does not lead to an actual switching to another thread —
* typically execution continues in the same thread.
Run Code Online (Sandbox Code Playgroud)

所以基本上它们无论如何都运行在同一个线程上。有真正的区别还是最终每个人使用都无关紧要?

谢谢!

Fra*_*esc 56

不同之处在于Dispatchers.Default它受限于 CPU 内核的数量(最少为 2 个),因此只有 N 个(其中 N == cpu 内核)任务可以在此调度程序中并行运行。

在 IO 调度器上默认有 64 个线程,因此该调度器上最多可以运行 64 个并行任务。

这个想法是 IO 调度程序花费大量时间等待(IO 阻塞),而默认调度程序用于 CPU 密集型任务,其中很少或没有睡眠。

  • 应该注意的是,“Dispatchers.Default”的存在是因为如果你的协程是 CPU 绑定的,那么在比你拥有的核心更多的线程上运行它们只会在上下文切换和线程开销上浪费时间,但如果你是这样,你仍然需要比核心更多的线程。执行阻塞 IO,因此是“Dispatchers.IO”。 (5认同)
  • 数据库查询是一个IO操作,因此应该使用IO调度程序。 (3认同)
  • @TeyyihanAksu `Dispatchers.IO` 和 `Dispatchers.Default` 确实共享相同的线程池,因此它们之间的切换不需要切换线程,但这只是一种优化。从概念上讲,您可以将它们视为不同的线程池。一个为每个 CPU 核心一个线程(“Dispatchers.Default”),另一个以“kotlinx.coroutines.io.parallelism”作为线程数(“Dispatchers.IO”)。 (3认同)

Mar*_*nik 27

所以基本上它们无论如何都运行在同一个线程上。有真正的区别还是最终每个人使用都无关紧要?

您在文档中的引述只是详细说明了 Kotlin 引入的优化:在Default和之间切换上下文时IO,您无需支付昂贵的切换到另一个线程的费用;相反,线程本身移动到另一个池。

这不会影响DefaultIO调度程序后面的线程池的整体属性:

  • Default 有一个固定大小的硬编码到可用处理器的数量,因为这对 CPU 密集型任务有意义。
  • IO是一个具有可配置最大大小的弹性线程池。该池中的线程预计大部分时间都处于不可运行状态,等待 IO 操作完成,因此拥有比 CPU 内核更多的线程是有意义的。

  • 您能否提供有关“线程本身移至另一个池”的更多信息。谢谢 :) (2认同)
  • 属于池的线程是一个簿记问题。如果将“Thread”对象从 IO 的线程列表移动到 Default 的线程列表,则您已将线程移动到另一个池。 (2认同)