将集合投影为任务并等待所有完成



我正在尝试并行化从集合发出的工作,并等待所有任务的完成。

这基本上是我所拥有的:

public Task<int> DoWorkAsync(int arg){
    return Task.Factory.StartNew(()=> {
        Thread.Sleep(1000);
        return arg*2;
    });
}

public async void DoAllWorks(){
    ICollection<int> workToDo = GetSomeWorkFromSomewhere();
    IEnumerable<Task<int>> tasks = workToDo.Select(i=> DoWorkAsync(i));

    int[] results = await Task.WhenAll(tasks);
    Debug.Write(results.Sum()); // Never called
}

public void Main(){
    DoAllWorks();
    // rest of code, which is called
    OtherMethods();
}

但是,WhenAll 方法会立即退出,其余代码将运行,即使仍有工作在执行。

如何解决?

您正在使用的async void只应用于事件处理程序。

使用async void时,无法等待async操作完成(同步或异步)。这意味着它会"触发"DoAllWorks并继续前进,因为它不知道DoAllWorks何时完成。 await Task.WhenAll(tasks) DoAllWorks 内部等待得很好,但调用方法已经移动。

在这种情况下,您应该返回一个可以awaitWait()的任务,因为Main无法自行async

public void Main()
{
    DoAllWorks().Wait();
    // rest of code, which is called
    OtherMethods();
}
public async Task DoAllWorks()
{
    ICollection<int> workToDo = GetSomeWorkFromSomewhere();
    IEnumerable<Task<int>> tasks = workToDo.Select(i=> DoWorkAsync(i));
    int[] results = await Task.WhenAll(tasks);
    Debug.Write(results.Sum());
}

事件处理程序外,不应使用异步 void。如果你返回一个任务,你可以在main方法中等待它await关键字或类似:

DoAllWorks().Wait();

仅供参考,您不需要使用 Thread.Sleep(1000); .您可以稍微重写代码以与构造async/await更一致

return Task.Run(async ()=> {
    await Task.Delay(1000);
    return arg*2;
});

最新更新