C# 4.0 WaitAll()未按预期执行
我已经编写了以下模拟代码作为我所看到的示例。我希望任务能在一秒钟多一点的时间内完成,因为它们都需要等待一秒钟。相反,完成任务大约需要41秒。为什么它在41秒内完成,而不是预期的1秒C# 4.0 WaitAll()未按预期执行,c#-4.0,task,C# 4.0,Task,我已经编写了以下模拟代码作为我所看到的示例。我希望任务能在一秒钟多一点的时间内完成,因为它们都需要等待一秒钟。相反,完成任务大约需要41秒。为什么它在41秒内完成,而不是预期的1秒 Task[] tasks = new Task[1000]; DateTime startTime = DateTime.Now; for (int i = 0; i < 1000; i++) { // allocate room in the list for the items we are goi
Task[] tasks = new Task[1000];
DateTime startTime = DateTime.Now;
for (int i = 0; i < 1000; i++)
{
// allocate room in the list for the items we are going to insert
Task task = Task.Factory.StartNew(() => Thread.Sleep(1000));
tasks[i] = task;
}
Task.WaitAll(tasks);
DateTime endTime = DateTime.Now;
TimeSpan span = endTime - startTime;
Task[]tasks=新任务[1000];
DateTime startTime=DateTime.Now;
对于(int i=0;i<1000;i++)
{
//在列表中为我们要插入的项目分配空间
Task Task=Task.Factory.StartNew(()=>Thread.Sleep(1000));
任务[i]=任务;
}
Task.WaitAll(任务);
DateTime endTime=DateTime.Now;
时间跨度=结束时间-开始时间;
您的每个任务都会被推送到线程池中,但这与为每个任务分配自己的线程并立即运行它不同。线程池不会使用无限数量的线程,因为您没有无限数量的CPU内核。同时运行1000个线程通常会比较慢,因为当许多线程争用少数可用内核时,所有上下文都会切换
相反,线程池尝试选择一个最佳的线程数,以在保持所有内容移动和不具有太多上下文切换之间取得平衡,从而获得尽可能好的(或至少非常好的)吞吐量。1000个任务每运行1秒除以约40秒意味着池中有25个线程
在这种情况下,您可能可以使用更高的线程数安全地运行,因为每个任务所做的只是睡眠。但threadpool不知道这一点。它期望您能够在CPU中完成这些任务的实际工作,并据此进行了设计。即使在这里,也要记住,即使只有25个线程,您也已经有了整整一秒钟的开销
最后,我经常遇到这样的代码,这些代码使用多个线程来分割CPU上的工作,结果发现真正的瓶颈是磁盘或网络I/O。始终值得提醒自己,磁盘的速度非常快,如果您试图分割来自文件、网络流或数据库的工作,您的CPU可能比您的数据源快很多,并且您可能不会获得太多(如果有的话)。这并不意味着“停止”,但它确实意味着您还需要花时间来衡量,以确保这种额外的代码复杂性是值得的。您的每个任务都被推送到线程池中,但这与为每个任务分配自己的线程并立即运行它并不相同。线程池不会使用无限数量的线程,因为您没有无限数量的CPU内核。同时运行1000个线程通常会比较慢,因为当许多线程争用少数可用内核时,所有上下文都会切换 相反,线程池尝试选择一个最佳的线程数,以在保持所有内容移动和不具有太多上下文切换之间取得平衡,从而获得尽可能好的(或至少非常好的)吞吐量。1000个任务每运行1秒除以约40秒意味着池中有25个线程 在这种情况下,您可能可以使用更高的线程数安全地运行,因为每个任务所做的只是睡眠。但threadpool不知道这一点。它期望您能够在CPU中完成这些任务的实际工作,并据此进行了设计。即使在这里,也要记住,即使只有25个线程,您也已经有了整整一秒钟的开销 最后,我经常遇到这样的代码,这些代码使用多个线程来分割CPU上的工作,结果发现真正的瓶颈是磁盘或网络I/O。始终值得提醒自己,磁盘的速度非常快,如果您试图分割来自文件、网络流或数据库的工作,您的CPU可能比您的数据源快很多,并且您可能不会获得太多(如果有的话)。这并不意味着“停止”,但它确实意味着您还需要花时间来衡量,以确保这种额外的代码复杂性是值得的