使用多线程协程有什么好处?

What profit of using multi-threaded coroutines?

我使用协程很长时间了,但我仍然不完全理解,为什么我需要更喜欢多线程协程而不是单线程协程。

当协程的数量小于或等于物理线程数时,我可以清楚地看到使用多线程协程的好处。但是如果我们有比物理线程更多的任务,为什么我们不宁愿只使用一个协程线程呢?

我将澄清最后一个问题:为什么 10 个协程线程比只有一个线程和许多协程更好?

协程是计算单元(如任务)。它们被分派到实际线程的方式与您拥有的协程数量是正交的。您可以使用单线程调度程序或多线程调度程序,并且根据此您的协程将被不同地调度。

多线程协程并不意味着每个协程 1 个线程。您可以在 8 个线程上分派 100 个协程。

But if we have more tasks than physical threads, why wouldn't we rather use only one coroutine thread?

这个问题有多个部分。

首先,如果您的任务多于逻辑核心,您仍然可以将所有这些任务分派到恰好数量的线程上。您不必完全放弃多线程。这实际上正是 Dispatchers.Default 的意义所在:将任意数量的协程分派到与您拥有的硬件线程(逻辑核心)数量相等的有限数量的线程上。重点是尽可能多地利用所有硬件,而不浪费 theads(以及内存)。

其次,并非每个任务都是 CPU-绑定的。一些 I/O 操作会阻塞线程(网络调用、磁盘 reads/writes 等)。当线程在 I/O 上被阻塞时,它不会使用 CPU。如果您有 8 个逻辑核心,那么 I/O 仅使用 8 个线程将不是最佳选择,因为虽然某些线程被阻塞,但 CPU 不能 运行 其他任务。使用更多线程,它可以(以一些内存为代价)。这就是Dispatchers.IO的重点,可以根据需要创建更多的线程,可以超过逻辑核心数(在合理的限度内)。

Why is 10 threads of coroutines better than only one thread with many coroutines?

假设您有 100 个协程要分派。

仅对 运行 这些协程使用一个线程意味着在给定时间最多只有 1 个核心在执行工作,因此没有并行发生。这意味着所有其他核心都处于空闲状态,这是次优的。更糟糕的是,协程完成的任何 I/O 操作都会阻塞这个唯一的线程,并阻止 CPU 在我们等待 I/O.

时做任何事情

使用 10 个线程,如果您的硬件足够,您实际上可以同时执行 10 个协程,这可以快 10 倍(如果您的协程没有相互依赖性)。

如果您的协程受 CPU 约束,则使用 100 个线程不会那么有益,但如果您有一堆 I/O 任务(如我们所见),则可能会有用。也就是说,您使用的线程越多,消耗的内存就越多。因此,即使有大量 I/O 操作,您也必须在吞吐量和内存之间找到平衡,您不想产生数百万个线程。

简而言之,无论是否使用协程,使用多线程仍然具有相同的优势:它允许尽可能多地利用您的硬件资源。使用协程只是定义任务、将任务分派到线程、表达依赖关系、避免不必要地阻塞线程等的一种更简单的方法。