NumberOfWorkers 和 MaxParallelism 选项的目的或关系是什么?
What is the purpose or relationship of NumberOfWorkers and MaxParallelism options?
前几天我遇到了一个问题,我将工作人员 SetNumberOfWorkers
扩展到一个可笑的数字,希望看到吞吐量的同等增长。我一次只能看到 5 名工人在做任何工作。发现魔术上限是最大并行度选项默认值为 5。
我的假设是 1 个工作线程等于 1 个线程。
NumberOfWorkers
和 MaxParallelism
选项的目的或关系是什么?
虽然我意识到它可能不是很清楚,但实际上很简单。
你完全正确,"number of workers" 是这个特定总线实例中的工作线程数。
但由于现在 Rebus 中的所有内容都是 async
,如果可以 await
ed,一个工人可以并行执行大量的工作。
因此 - 为了避免做太多工作 - 引入了 "max parallelism" 概念,它对要并行处理的消息数量设置了全局最大上限。
使用哪些值取决于您要执行的工作类型。以下是一些合理的设置:
- 工作主要是异步的 - 您可以使用一些工作线程和相当高的并行度,例如
.SetNumberOfWorkers(2).SetMaxParallelism(20)
- 工作快速并且是同步的 - 您可以使用一些工作线程和匹配的并行度,例如
.SetNumberOfWorkers(5).SetMaxParallelism(5)
(尽管在这种情况下将并行度设置得更高不会有任何影响)
- 工作慢并且是同步的——您可以使用更多的工作线程和匹配的并行度,例如
.SetNumberOfWorkers(15).SetMaxParallelism(15)
(再次说明:在这种情况下,将并行度设置得更高不会有任何影响)
正如您正确观察到的那样,由于并行度设置对可以并行处理的消息数设置了绝对上限,因此将并行度设置为低于线程数没有意义。
编辑:我已将 this page 添加到 wiki - 感谢您让我意识到这个概念在任何地方都没有解释:)
我查看了 Rebus 代码,似乎混合了普通线程和线程池线程 - worker 本身就是一个普通线程,但它会生成多个 TPL 任务,并且不会等到该任务完成后立即执行尝试生成另一个(如果消息的接收及其处理确实是异步的,它可以做到这一点)。阻止它生成无限数量任务的原因是:
var parallelOperation = _parallelOperationsManager.TryBegin();
if (!parallelOperation.CanContinue())
{
_backoffStrategy.Wait();
return;
}
parallelOperationsManager 阻止它生成超过 MaxParallelism 的异步任务。它在尝试生成新任务之前使用信号量计数器。如果计数器达到 MaxParalleism 的数量,则线程会在短时间内被 Thread.Sleep 阻塞,以便有时间完成 运行 任务,减少信号量计数器,并允许产生新的任务(读取后端队列并处理消息)。
所以本质上 - worker 数量 - 是普通 NET Framework 线程的数量,而 MaxParallelism 是任务的最大数量(实际上不是线程池线程的数量,但它们可以使用线程池用于异步执行)
如果没有 MaxParallelism 约束,单个 Worker(普通线程)可能会生成数百万个 IO 绑定异步任务,但无论如何只能处理单个同步任务。
如果作业是完全同步的,那么它将在普通线程上处理,如果作业包含等待异步操作,那么异步代码点之前的作业将在普通线程上完成在线程池线程上等待之后。
前几天我遇到了一个问题,我将工作人员 SetNumberOfWorkers
扩展到一个可笑的数字,希望看到吞吐量的同等增长。我一次只能看到 5 名工人在做任何工作。发现魔术上限是最大并行度选项默认值为 5。
我的假设是 1 个工作线程等于 1 个线程。
NumberOfWorkers
和 MaxParallelism
选项的目的或关系是什么?
虽然我意识到它可能不是很清楚,但实际上很简单。
你完全正确,"number of workers" 是这个特定总线实例中的工作线程数。
但由于现在 Rebus 中的所有内容都是 async
,如果可以 await
ed,一个工人可以并行执行大量的工作。
因此 - 为了避免做太多工作 - 引入了 "max parallelism" 概念,它对要并行处理的消息数量设置了全局最大上限。
使用哪些值取决于您要执行的工作类型。以下是一些合理的设置:
- 工作主要是异步的 - 您可以使用一些工作线程和相当高的并行度,例如
.SetNumberOfWorkers(2).SetMaxParallelism(20)
- 工作快速并且是同步的 - 您可以使用一些工作线程和匹配的并行度,例如
.SetNumberOfWorkers(5).SetMaxParallelism(5)
(尽管在这种情况下将并行度设置得更高不会有任何影响) - 工作慢并且是同步的——您可以使用更多的工作线程和匹配的并行度,例如
.SetNumberOfWorkers(15).SetMaxParallelism(15)
(再次说明:在这种情况下,将并行度设置得更高不会有任何影响)
正如您正确观察到的那样,由于并行度设置对可以并行处理的消息数设置了绝对上限,因此将并行度设置为低于线程数没有意义。
编辑:我已将 this page 添加到 wiki - 感谢您让我意识到这个概念在任何地方都没有解释:)
我查看了 Rebus 代码,似乎混合了普通线程和线程池线程 - worker 本身就是一个普通线程,但它会生成多个 TPL 任务,并且不会等到该任务完成后立即执行尝试生成另一个(如果消息的接收及其处理确实是异步的,它可以做到这一点)。阻止它生成无限数量任务的原因是:
var parallelOperation = _parallelOperationsManager.TryBegin();
if (!parallelOperation.CanContinue())
{
_backoffStrategy.Wait();
return;
}
parallelOperationsManager 阻止它生成超过 MaxParallelism 的异步任务。它在尝试生成新任务之前使用信号量计数器。如果计数器达到 MaxParalleism 的数量,则线程会在短时间内被 Thread.Sleep 阻塞,以便有时间完成 运行 任务,减少信号量计数器,并允许产生新的任务(读取后端队列并处理消息)。
所以本质上 - worker 数量 - 是普通 NET Framework 线程的数量,而 MaxParallelism 是任务的最大数量(实际上不是线程池线程的数量,但它们可以使用线程池用于异步执行) 如果没有 MaxParallelism 约束,单个 Worker(普通线程)可能会生成数百万个 IO 绑定异步任务,但无论如何只能处理单个同步任务。
如果作业是完全同步的,那么它将在普通线程上处理,如果作业包含等待异步操作,那么异步代码点之前的作业将在普通线程上完成在线程池线程上等待之后。