在深入研究Coroutine的实现(如"Default“和"IO”)之后,我发现它们只包含一个Java执行器(这是一个简单的线程池)和一个Runnable队列(这是coroutine逻辑块)。
让我们以一个示例场景为例,在相同的coroutine上下文中启动10,000个协同器,例如“默认”dispatcher,其中包含一个执行器,池中有512个真正的线程。
这些协同线将被添加到调度器队列中(以防飞行中协同线的数量超过最大阈值)。
例如,让我们假设,我从10,000中启动的第一批512协同任务非常缓慢和沉重。
我的其他协同机制是否会被阻塞,直到至少有一个真正的线程完成,或者在这些“用户空间线程”中是否存在一些时间切片机制?
发布于 2021-08-20 12:18:37
协同调度是协作性的,而不是先发制人的,因此上下文切换只能在暂停点进行.这实际上是设计上的,它使执行速度快得多,因为协同机制不会互相对抗,上下文切换的数量也比抢占式调度中的少。
但正如你注意到的,它也有缺点。如果执行长CPU密集型计算,则建议不时调用产量()。它允许释放线程用于其他协同工作。另一种解决方案是为我们的计算创建一个不同的线程池,以便将它们与应用程序的其他部分分开。这与先发制人的调度有类似的缺点-它将使协同/线程争夺对CPU核心的访问。
发布于 2021-08-20 12:51:57
一旦协同线开始执行,它将继续执行,直到到达暂停点,这是通过调用suspendCoroutine或suspendCancellableCoroutine引入的。
暂停是基本理念。
但是,这是通过设计实现的,因为挂起对于coroutines引入的性能提升至关重要,协同背后的全部原因是,当线程只做等待时,为什么一直阻塞线程(例如同步IO)。为什么不使用这个线程来做其他的呢?
如果没有停职,你就会损失很多性能增益。
因此,为了在特定情况下识别开关,您必须定义术语slow and heavy。cpu密集型任务(如生成素数)可以是慢的和重的,在服务器上执行复杂计算然后返回结果的API调用也可以是慢的和重的。如果512个协同线没有暂停点,那么其他人将不得不等待它们完成。这实际上违背了使用协同线的全部意义,因为您有效地使用coroutiens代替线程,但增加了开销。
如果您必须并行执行一系列非挂起的操作,则应该使用像Executor这样的服务,因为在本例中,协同只会添加一个无用的抽象层.。
https://stackoverflow.com/questions/68861907
复制相似问题