在许多线程上执行具有不同参数的无序方法的最佳方法[关闭]

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();

【讨论】:

以上是关于在许多线程上执行具有不同参数的无序方法的最佳方法[关闭]的主要内容,如果未能解决你的问题,请参考以下文章

在后台运行无限操作而不影响主线程的最佳方法?

Multithreading in Java

管理具有不同价格的多个并发订阅的计费周期的最佳方法是啥?

将许多参数传递给方法的最佳实践?

最佳后台处理/API 调用方法?

在Django中实现具有许多重叠字段的模型的最佳方法?