C#如何从Task []中删除已完成的Task

时间:2019-12-04 02:59:52

标签: c# arrays task .net-4.5

我有一个这样运行的任务数组:(数组中的任务数不固定为2,它可能会不时变化)。

Task[] templates = new Task[2] {
  Task.Factory.StartNew( () => { x.foo(); }),
  Task.Factory.StartNew( () => { y.bar(); })
};

然后我等待其中任何一个完成。

int taskID;
taskID = Task.WaitAny(templates);

任务完成后,我将检查对象内的各种参数(x或y),如果没有结果,我希望从模板数组中删除完成的任务。像这样

template[taskID].RemoveThisTaskFromArray() // This is pseudo code to describe what I want.
taskID = Task.WaitAny(templates);

我将循环执行此操作,直到任务数组template[]为空,或者我决定中止该操作并退出循环为止。

int taskID;
do {
  taskID = Task.WaitAny(templates);
  if(template[taskID].valid == true) { // <-- example of test for success
    // stop the remaining task in the template[] array.
    break;
  }

  // remove the completed task so we can use WaitAany() again.

} while (template.Length > 0);

似乎Task[]不支持数组成员,因此没有Task[].RemoveAt()函数。 希望你明白我的意思。有什么办法解决这个问题?

2 个答案:

答案 0 :(得分:1)

只需使用List<Task>即可。但是,出于described in detail here的原因,请使用Task.Run代替Task.Factory.StartNew

var templates = new List<Task> {
  Task.Run( () => { x.foo(); }),
  Task.Run( () => { y.bar(); })
};
int taskID;
do {
  taskID = Task.WaitAny(templates.ToArray());
  if(templates[taskID].valid == true) { // <-- example of test for success
    // stop the remaining task in the template[] array.
    break;
  }

  templates.RemoveAt(taskID);

} while (template.Count > 0);

这将调用.ToArray(),这将创建一个新数组(preserving order),因此效率稍低,但是可以正常工作。这确实是提供Task.WaitAll所需数组的最简单方法,同时保留了轻松删除项目的能力。

但是我不知道您打算如何使用template[taskID].valid。您是否要使用templates(带有's')数组? (这就是我的假设)但是Task没有任何称为valid的属性。您是说看看Status属性吗?

但是,您可以考虑使用asyncawait并使用Task.WhenAny来避免在等待时阻塞当前线程。 Task.WhenAll也接受任何IEnumerable,因此您无需致电.ToArray()

do {
  var doneTask = await Task.WhenAny(templates);

  // This will return any result, but also throw any exception that
  // might have happened inside the task.
  await doneTask;

  templates.Remove(doneTask);

} while (templates.Count > 0);

从这里开始,有一些写得很好的关于异步编程的文章:Asynchronous programming with async and await

答案 1 :(得分:0)

可以使用linq这样从任务列表中删除完成的任务

templates.RemoveAll(x => x.IsCompleted);