如何等待并行Linq操作完成

时间:2014-10-26 20:42:33

标签: c# linq task-parallel-library async-await parallel-extensions

我不确定我应该如何混合plinq和async-await。假设我有以下界面

public interface IDoSomething (
    Task Do();
}

我有一个列表,我想并行执行这些列表并能够await完成所有这些。

public async Task DoAll(IDoSomething[] doers) {
    //Execute all doers in parallel ideally using plinq and 
    //continue when all are complete
}

如何实现?我不确定如何从并行linq转到任务,反之亦然。

我对异常处理并不十分担心。理想情况下,第一个会触发并打破整个过程,因为我打算在出错时丢弃整个过程。

编辑:很多人都在说Task.WaitAll。我意识到这一点,但我的理解(除非有人能证明不是这样)是因为它不会主动将你的东西并行化到多个可用的处理器核心。我特别要求的是双重的 -

  1. 如果I await Plinq Action中的Task确实可以摆脱很多优势,因为它会安排一个新线程吗?

  2. 如果我doers.AsParallel().ForAll(async d => await d.Do())平均需要大约5秒钟,那我怎么不在此期间转动调用线程呢?

2 个答案:

答案 0 :(得分:7)

您正在寻找的是:

public Task DoAllAsync(IEnumerable<IDoSomething> doers)
{
    return Task.WhenAll(doers.Select(doer => Task.Run(() => doer.Do())));
}

使用Task.Run将使用ThreadPool线程并行执行async方法Do的每个同步部分,而Task.WhenAll异步等待异步部分同时执行的一起。


如果您在这些async方法(例如await之前的部分)中有大量同步部分,那么这是一个好主意,例如:

async Task Do()
{
    for (int i = 0; i < 10000; i++)
    {
        Math.Pow(i,i);
    }

    await Task.Delay(10000);
}

否则,不需要并行性,您可以同时触发异步操作并使用Task.WhenAll等待所有返回的任务:

public Task DoAllAsync(IEnumerable<IDoSomething> doers)
{
    return Task.WhenAll(doers.Select(doer => doer.Do()));
}

答案 1 :(得分:1)

public async Task DoAll(IDoSomething[] doers) {
    //using ToArray to materialize the query right here
    //so we don't accidentally run it twice later.
    var tasks = doers.Select(d => Task.Run(()=>d.Do())).ToArray();
    await Task.WhenAll(tasks);
}