gpt4 book ai didi

c# - Parallel.ForEachAsync 的实际最大并发任务数

转载 作者:行者123 更新时间:2023-12-03 08:05:41 34 4
gpt4 key购买 nike

我预计此代码需要 1 秒才能执行:

public async void Test()
{
DateTime start = DateTime.Now;
await Parallel.ForEachAsync(new int[1000], new ParallelOptions { MaxDegreeOfParallelism = 1000 }, async (i, token) =>
{
Thread.Sleep(1000);
});
Console.WriteLine("End program: " + (DateTime.Now - start).Seconds + " seconds elapsed.");
}

相反,在我的电脑(i7-9700 8 核 8 线程)上需要 37 秒:

End program: 37 seconds elapsed.

我使用 MaxDegreeOfParallelism = 1000 生成 1000 个任务......为什么它们不同时运行?

最佳答案

Parallel.ForEachAsync方法调用 ThreadPool 上的异步 body 委托(delegate)线程。通常此委托(delegate)会快速返回一个 ValueTask ,但在您的情况下,情况并非如此,因为您的委托(delegate)并不是真正的异步:

async (i, token) => Thread.Sleep(1000);

您可能会收到有关缺少 await 运算符的 async 方法的编译器警告。尽管如此,为 Parallel.ForEachAsync 方法提供混合的同步/异步工作负载是可以的。此方法旨在处理任何类型的工作负载。但如果工作负载大部分是同步的,结果可能是线程池饱和。

ThreadPool 已经创建了 SetMinThreads 指定的线程数时,就被认为是饱和的。方法,默​​认等于 Environment.ProcessorCount ,并且有更多的工作需要完成。在这种情况下,ThreadPool 切换到一种保守算法,每秒创建一个新线程(从 .NET 6 开始)。此行为没有准确记录,并且可能在未来的 .NET 版本中发生变化。

为了获得您想要的行为,即并行运行所有 1000 个输入的委托(delegate),您必须增加 ThreadPool 根据需要立即创建的线程数:

ThreadPool.SetMinThreads(1000, 1000); // At the start of the program

有人会说,这样做之后您将不再拥有线程池,因为线程池意味着一个可重用线程的小型池。但是,如果您不关心语义而只想完成工作,那么无论后果如何,memory consumption以及操作系统级别的开销,这是解决问题的最简单方法。

关于c# - Parallel.ForEachAsync 的实际最大并发任务数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72447990/

34 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com