C# TPL如何知道所有任务都已完成?

8

我有一个循环来生成任务。

代码:

Task task = null;
foreach (Entity a in AAAA)
{
  // create the task 
  task = new Task(() => {
    myMethod(a);
  },  Token, TaskCreationOptions.None);
  task.Start();
}

在每个迭代中,可以看到任务对象都有新的初始化(..new Task(() =>..))。如何知道所有任务都已完成?

3个回答

23
如果您将此替换为

 Parallel.ForEach(...,  () => myMethod(a), ...)

然后你会在ForEach结尾自动等待所有任务完成。

也许可以从一个单独的Task中运行ForEach。


抢先一步了。希望我能多次点赞。毕竟这是一个很好的“不要重复造轮子”的例子。 - Rune FS
3
问题是,在创建任务的循环和使用Parallel.ForEach之间存在一些非常真实的性能差异/差别。虽然它们在许多情况下可能相似,但不应该盲目地将它们替换为彼此来解决无关的问题。 - Andrew Anderson
@Andrew,你说得对。我之前没有注意到它,因为mymethod(a)不够具体,并且缺乏相关情况的信息。 - H H

13
var allTasks = new List<Task>();
foreach (Entity a in AAAA)
{
  // create the task 
  task = new Task(() => {
    myMethod(a);
  },  Token, TaskCreationOptions.None);

  // Add the tasks to a list
  allTasks.Add(task);
  task.Start();
}

// Wait until all tasks are completed.
Task.WaitAll(allTasks.ToArray());

很好 - 我认为你需要输入列表 List<Task>,这样 .ToArray() 就会生成一个任务数组而不是对象。 - Rup

8

您需要在循环中保留对所有任务的引用。然后,您可以使用Task.WaitAll方法(请参见MSDN参考)。您可以创建一个数组并将任务分配给数组的元素(在C# 2.0中),也可以使用LINQ:

var tasks = 
   AAAA.Select((Entity a) => 
      Task.Factory.StartNew(() => { myMethod(a); },
         Token, TaskCreationOptions.None)).ToArray();
Task.WaitAll(tasks)

如果你不需要使用任务(显式地),那么Henk的建议使用Parallel.ForEach可能是更好的选择。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接