为什么这些任务开始延迟?

时间:2016-03-09 09:47:58

标签: c# multithreading task

我正在尝试这段代码(只产生一些任务并模拟工作):

var tasks = Enumerable.Range(1, 10).Select(d => Task.Factory.StartNew(() =>
{
    Console.Out.WriteLine("Processing [{0}]", d);
    Task.Delay(20000).Wait(); // Simulate work. Here will be some web service calls taking 7/8+ seconds.
    Console.Out.WriteLine("Task Complete [{0}]", d);
    return (2 * d).ToString();
})).ToList();

var results = Task.WhenAll(tasks).Result;
Console.Out.WriteLine("All processing were complete with results: {0}", string.Join("|", results));

我原本希望在控制台中同时看到10个Processing ...;但是当我跑步时,我最初看到了这个输出

Processing [1]
Processing [2]
Processing [3]
Processing [4]

然后半秒后Processing [5]Processing [6]和其他人一个接一个地缓慢显示。

你能解释一下吗?这是否意味着任务正在延迟启动?为什么呢?

2 个答案:

答案 0 :(得分:3)

如另一个答案中所述,使用TaskCreationOptions.LongRunning将解决您的问题。

但这不是你应该如何处理你的问题。您的示例模拟 CPU绑定工作。您说您的任务将调用Web服务 - 这意味着它们将 IO绑定

因此,它们应该以异步方式运行 。但是,Task.Delay(20000).Wait();等待同步,因此它不代表将要/应该实际发生的事情。

改为举例:

var tasks = Enumerable.Range(1, 10).Select(async d =>
{
    Console.Out.WriteLine("Processing [{0}]", d);
    await Task.Delay(5000); // Simulate IO work. Here will be some web service calls taking 7/8+ seconds.
    Console.Out.WriteLine("Task Complete [{0}]", d);
    return (2*d).ToString();
}).ToList();
var results = Task.WhenAll(tasks).Result;
Console.Out.WriteLine("All processing were complete with results: {0}", string.Join("|", results));

所有任务都按预期立即启动。

答案 1 :(得分:1)

我希望你有4个cpu核心。

让两个(cpu bond)线程争夺核心导致它需要更长时间才能完成工作,然后让1个线程执行第一个任务,然后执行第二个任务。

除非另有说明,否则任务系统会假定任务运行时间短且CPU受限,并且他们将使用“无阻塞”IO。

因此,我希望任务系统默认为接近核心数的线程数。

使用TaskCreationOptions.LongRunning

  

向TaskScheduler提供了超额订阅的提示   必要的。 Oversubscription允许您创建更多的线程   可用的硬件线程数。

最后任务不是线程,它们的设计是隐藏线程的大量细节,包括控制正在使用的线程数。创建100s是合理的任务,如果你创建的100个线程都试图同时运行,那么cpu cache等将会非常困难。

然而,让我们回到你想要做的事情。您的示例模拟CPU绑定工作。您说您的任务将调用Web服务 - 这意味着它们将受IO限制。

因此,它们应该异步运行。但是,Task.Delay(20000).Wait();会同步等待,因此它不代表将要/应该实际发生的事情。有关使用await进行异步延迟的代码示例,请参阅Gediminas Masaitis答案。但是,只要您使用更多异步代码,就需要更多地考虑锁定等问题。

如果同时发出100个请求,异步IO显然会更好。但是,如果您的应用程序中只有“手满”并且没有使用await,那么TaskCreationOptions.LongRunning可能就足够了。