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

Project a collection as task and wait for all completion

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

这里基本上是我所拥有的:

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 操作完成(同步或异步)。这意味着它 "fires" DoAllWorks 并继续前进,因为它不知道 DoAllWorks 何时完成。 await Task.WhenAll(tasks) inside DoAllWorks 等待得很好,但是调用方法已经继续了。

你应该 return 一个任务,而不是你可以 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());
}

除事件处理程序外,您不应使用 async void。如果你 return 一个任务,你可以在主方法中使用 await 关键字或类似的方法等待它:

DoAllWorks().Wait();

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

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