如何使用 LINQ 等待 ParallelQuery?

How to await a ParallelQuery with LINQ?

我有一个异步方法,它应该查找数据库条目。它按名称过滤,因此是并行执行的候选者。

但是,我找不到同时支持并行执行和异步任务的简单方法。

这是我拥有的:

private async Task<List<Item>> GetMatchingItems(string name) {
    using (var entities = new Entities()) {
        var items =  from item in entities.Item.AsParallel()
               where item.Name.Contains(name)
               select item;
        return await items.ToListAsync(); //complains "ParallelQuery<Item> does not contain a definition for ToListAsync..."
    }
}

当我删除 AsParallel() 时它会编译。 A 我不应该同时使用这两个功能?还是我理解有误?

IHMO,两者都有意义:

如何同时使用并行执行(使用 LINQ)和异步任务?

嗯,你不能。这是 2 个不同的选项,不能放在一起。

您可以使用 Task.Runasync-await 在多个 ThreadPool 线程上并行化异步操作的同步部分(即第一个 await 之前的部分),但没有内置到 PLINQ 中的所有分区逻辑,例如:

var tasks = enumerable.Select(item => Task.Run(async () => 
{
    LongSynchronousPart(item);
    await AsynchronouPartAsync(item);
}));
await Task.WhenAll(tasks);

然而,在您的情况下(假设它是 Entity Framework),使用 PLINQ 没有任何价值,因为没有实际的并行化工作。查询本身在数据库中执行。

你不能,也不应该。 PLINQ 不适用于数据库访问。数据库最了解如何并行化查询,并使用普通的 LINQ 自行完成。 PLINQ 用于访问对象,例如在 LINQ 查询中进行计算量大的计算,因此它可以在客户端并行化(相对于在 server/database 服务器端并行化)。

更好的答案可能是: PLINQ 用于跨多个线程分发计算密集型查询。 异步用于 return 返回线程以便其他人可以使用它,因为您将等待外部资源(数据库、磁盘 I/O、网络 I/O 等)。

Async PLINQ 没有非常强大的用例,您希望在等待时 return 线程并且您有很多计算要做...如果您忙于计算,则需要线程(或多个线程)。它们几乎完全处于优化的不同端。如果你需要这样的东西,有更好的机制,如任务等。