在许多线程上执行具有不同参数的无序方法的最佳方法[关闭]
Posted
技术标签:
【中文标题】在许多线程上执行具有不同参数的无序方法的最佳方法[关闭]【英文标题】:Best way to execute a method unordered with different parameters over many threads [closed] 【发布时间】:2021-05-14 13:59:36 【问题描述】:我有一个很大的数字列表(其中 4,718,515 个),我需要对每个数字运行一个方法。
我有一个方法 Check(number)
需要与 numbers
中的项目一起运行。
我不知道在 c# 中最有效的方法
如果有帮助,这里有一些例子说明我是如何用其他语言做到这一点的
蟒蛇:
pool.imap_unordered
在 Java 中:
forkJoinPool = new ForkJoinPool(processes);
forkJoinPool.submit(() -> words.stream()
.unordered()
.parallel()
.filter(CheckValidity::checkValidity)
【问题讨论】:
在一个号码上运行Check(number)
会影响在任何其他号码上运行它吗?您可以完全并行运行它们,而不关心排序吗?如果是这样,请查看Parallel.ForEach
。它将在线程池线程集上进行相当好的分区工作。以我的经验,它在并行处理受 CPU 限制的独立工作方面做得很好。顺便说一句,我不是 Java 专家,但你的 Java 代码中有不平衡的括号
@Flydog57 是的,Java 代码中还有一些代码,但这个问题没有必要,所以我把它删掉了。 Check(number) 不会影响任何其他数字,所以我会确保查看Parallel.ForEach()
您可能想在您的问题中添加一些 C# 代码,例如显示numbers
的类型。也许像IEnumerable<int> numbers = Get4MillionNumbers(); numbers.DoInParallelSomehow(number => Check(number));
这样的东西并解释它的含义
因为你可能做了很多研究(比如阅读类似的问题bing.com/…)请edit这个问题来证明该研究的结果。这将有助于缩小建议范围,因为显然您已经尝试过标准的 Parallel.*
和 Task.WhenAll
方法,但这些方法并没有带来可接受的结果。
除非每次调用Check(number)
都很昂贵,否则使用线程并没有太大帮助。如果电话费用很高,那么4,718,515
号码可能仍需要很长时间。如果每次通话需要一秒钟,您可能会将时间从 55 天减少到大约 7 天。
【参考方案1】:
试试这个:
Parallel.ForEach(numbers, number => Check(number));
Parallel.ForEach method 尝试使用多个线程并行运行 Check
操作。
【讨论】:
我建议在使用Parallel
类时将MaxDegreeOfParallelism
明确指定为一个合理的值(如Environment.ProcessorCount
)。它的默认值为-1
,表示无限并行。这会导致ThreadPool
立即饱和,并保持饱和状态直到源可枚举完成。
这是真的吗?有几次我使用 Parallel.ForEach(从不设置 MaxDegreeOfParallelism
),我看到它在 N 个逻辑核心系统上运行 N 个线程。我记得最多的时候,该应用程序主要在一个 4 核机器上执行 CPU 密集型工作,每个项目大约需要 1-5 秒。我们记录了开始和停止。看着它从 1-4 开始、3 结束、5 开始、2 结束、6 开始、3 结束、7 开始等等,这很有趣
来自:docs.microsoft.com/en-us/dotnet/api/…“一般情况下,您不需要修改此设置。”。它确实这样说:“如果是-1,则对并发运行的操作数没有限制。”,但它并没有说它会使线程池饱和,它说它会使用“线程池的启发式算法...确定要使用的正确线程数”。根据我的经验,默认行为效果很好。
@Flydog57 它工作得很好,前提是你的程序在并行执行期间什么都不做。如果您还有一些System.Timers.Timer
滴答声,或者一些由多个await
点在内部组成的动态异步方法,那么饱和的ThreadPool
将导致所有异步回调的打嗝和延迟。
@TheodorZoulias:这令人惊讶。我上面给出的那个例子是真实的。大约有 35 个工作单元。在 4 核机器上,我可以看到四个线程立即启动,然后随着每个线程完成之前的工作而开始新的工作。产品盒是 8 核的。我通常不会完全登录 prod,但出于好奇,有一天我更改了配置以查看它的行为。我看到分派了 8 份工作,然后每次完成前一个工作单元时都会派发新的工作。嗯【参考方案2】:
在 C# 中有 PLINQ 库
var desiredResult = numbers
.AsParallel()
.AsUnordered()
.Where(number => Check(number))
.ToArray();
【讨论】:
以上是关于在许多线程上执行具有不同参数的无序方法的最佳方法[关闭]的主要内容,如果未能解决你的问题,请参考以下文章