我在网上找到了一段代码并对其进行了一些修改以查看其工作原理,但是现在我遇到了问题
ContinueWhenAll
因为它不会等待所有任务完成:
List<Task> tasks = new List<Task>();
for (int i = 0; i < 20; i++)
{
int j = i;
var compute = Task.Factory.StartNew(() => results.Add(DoSomething(j)));
tasks.Add(compute);
}
我正在使用此代码将所有任务添加到列表中。
DoSomething
函数计算一些结果并将它们添加到 BlockingCollection
。我有另一个显示功能,它将所有添加的结果从 BlockingCollection
写入控制台。
我已经使用这段代码等待所有任务完成,但看起来它并没有等待它们,因为程序在启动后仅几毫秒就显示了标准的
"Press any key to continue"
消息。 (程序完成需要大约 20 秒)
Task.Factory.ContinueWhenAll(tasks.ToArray(), result => results.CompleteAdding());
但是,如果我在程序末尾添加
Task.WaitAll(consume)
,程序运行良好:
var consume = Task.Factory.StartNew(() => display(results));
//results = BlockingCollection that I mentioned
据我所知,该程序没有足够的时间来显示
BlockingCollection
的所有结果,但它仍然有足够的时间在等待所有任务完成时显示一些结果。
有人能解释一下为什么 Task.Factory.ContinueWhenAll 不等待计算所有结果并且程序结束就像程序中没有那行代码一样(几毫秒后)?
Task.Factory.ContinueWhenAll
不是阻塞方法;它实际上会启动一个新任务,只有当所有提供的任务都在那里执行完成时才会起作用,所以在程序启动后几毫秒看到一条消息是正常的,因为它不会 block 在你的主要等待要完成的任务。
来自 msdn:
创建将在完成一组提供的任务后启动的延续任务。
Task.WaitAll
将 block 在调用者处等待所有提供的任务完成执行。
基于官方文档:
ContinueWhenAll
方法:
Creates a continuation task that starts when a set of specified tasks has completed.
所以它实际上是在创建一个新的Task,这不是阻塞操作。