实际的最大并行任务。
我希望此代码要执行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.");
}
相反,在我的PC上需要37秒(i7-9700 8核8-thread):
End program: 37 seconds elapsed.
我正在使用MaxDegreeofParallelism = 1000
生成1000个任务。 ...为什么他们都不同时运行?
I would expect this code to take 1 second to execute:
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.");
}
Instead, it takes 37 seconds on my pc (i7-9700 8-core 8-thread):
End program: 37 seconds elapsed.
I am generating 1000 tasks with MaxDegreeOfParallelism = 1000
....why don't they all run simultaneously?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
方法调用异步
body
threadpool
线程。通常,此委托会迅速返回valuettask
,但是在您的情况下,这不是发生的情况,因为您的代表并不是真正的异步:您可能会在这里发出编译器警告,关于
async 缺少
等待
运算符的方法。但是,将混合的同步/异步工作负载给并行。foreachAsync
方法还可以。此方法旨在处理任何类型的工作量。但是,如果工作负载主要是同步的,则可能是饱和的threadpool
。threadpool
已经创建了emovention.processorcount
,并且需要做更多的工作。在这种情况下,threadpool
切换到保守的算法,该算法每秒都会创建一个新线程(截至.NET 6)。这种行为不会精确记录,并且可能会在未来的.NET版本中改变。为了获得所需的行为,即在所有1000个输入中运行委托,您必须增加
threadpool
立即根据需求创建的线程数:有些人会这样做之后,您将不再有一个线程池,因为一个线程池意味着是一小池可重复使用的线程。但是,如果您不在乎语义,而只想完成工作,那么无论后果如何-c-sharp-extly-1-mb“>内存消耗在操作系统级别上的开销,这是解决问题的最简单方法。
The
Parallel.ForEachAsync
method invokes the asynchronousbody
delegate onThreadPool
threads. Usually this delegate returns aValueTask
quickly, but in your case this is not what happens, because your delegate is not really asynchronous:You are probably getting here a compiler warning, about an
async
method lacking anawait
operator. Nevertheless giving a mixed sync/async workload to theParallel.ForEachAsync
method is OK. This method is designed to handle any kind of workload. But if the workload is mostly synchronous, the result might be a saturatedThreadPool
.The
ThreadPool
is said to be saturated when it has already created the number of threads specified by theSetMinThreads
method, which by default is equal toEnvironment.ProcessorCount
, and there is more demand for work to be done. In this case theThreadPool
switches to a conservative algorithm that creates one new thread every second (as of .NET 6). This behavior is not documented precisely, and might change in future .NET versions.In order to get the behavior that you want, which is to run the delegate for all 1000 inputs in parallel, you'll have to increase the number of threads that the
ThreadPool
creates instantly on demand:Some would say that after doing so you won't have a thread pool any more, since a thread pool is meant to be a small pool of reusable threads. But if you don't care about the semantics and just want to get the job done, whatever the consequences are regarding memory consumption and overhead at the operating system level, that's the easiest way to solve your problem.
我不知道
foreachAsync
的确切实现,但我假设他们使用task
s,而不是thread
s。当您使用1000
任务
s运行1000 CPU绑定操作时,实际上并未创建1000thread
s,您只是在问一些thread> threadpool
线程
s运行这些操作。这些线程
s被Sleep
调用阻止,因此大多数任务
s在开始执行之前被排队。这就是为什么在
任务
中或一般的异步上下文中调用thread.sleep
是一个可怕的想法的原因。如果您编辑代码以异步而不是同步等待,那么经过的时间可能会更接近一秒钟。I do not know the exact implementation of
ForEachAsync
, but I assume that they useTask
s, notThread
s.When you use 1000
Task
s to run 1000 CPU bound operations, you are not actually creating 1000Thread
s, you are just asking a handful ofThreadPool
Thread
s to run those operations. ThoseThread
s are blocked by theSleep
calls, so most of theTask
s are queued up before they can start execution.This is exactly why it is a horrible idea to call
Thread.Sleep
in aTask
, or in async contexts in general. If you edit your code to wait asynchronously instead of synchronously, the time elapsed will probably be much closer to a second.