如何等待Parallel Linq操作完成

本文关键字:Linq 操作 Parallel 何等待 等待 | 更新日期: 2023-09-27 18:27:50

我不确定应该如何混合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. 如果我在Plinq操作中awaitTask,这是否消除了很多优点,因为它调度了一个新线程?

  2. 如果我doers.AsParallel().ForAll(async d => await d.Do())(平均耗时约5秒),如何在这期间不旋转调用线程?

如何等待Parallel Linq操作完成

您想要的是:

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()));
}
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);
}