这两个代码片段是否使用 IQueryable 和 .AsParallel 等效?

Are these two code snippets using IQueryable and .AsParallel equivalent?

我正在编写一些非常基本的 TPL 代码,我 运行 遇到了一种情况,我很好奇以下两个片段是否等效:

myEnumerable.AsParallel().Select(e =>
{
    //do some work that takes awhile
    return new Thing(e);
}

myEnumerable.Select(e =>
{
    //do some work that takes awhile
    return new Thing(e);
}.AsParallel()

此外 - 如果它们实际上是等价的,那么它们的等价性是否可以根据 TPL 接口与 IEnumerable 扩展方法的定义进行更改?还是我只是设置自己在更新到 .NET V{Whatever} 时破坏我的代码?

对于背景,myEnumerable 是一个 EF table(实体),我还没有枚举(进行数据库往返)。

我想要的行为是同步进行数据库调用,取回一个列表,并并行操作列表(并行地对列表进行一系列 Web 服务调用)

只有AsParallel之后的才是平行的。它之前的所有内容都只是并行查询的顺序输入流(例外:如果输入已经是并行查询,它将被视为并行查询)。

PLINQ 无法并行化现有查询,因为它无法剖析它。输入是不透明的 IEnumerable.

My desired behavior is for the DB call to be made synchronously, get a List back, and operate upon the list in parallel

使用第一个代码片段。

make a bunch of web service calls on the List in parallel

TPL 在为 IO 绑定任务选择最佳并行度方面表现不佳。使用 WithDegreeOfParallelism 为您的特定 IO 负载选择合适的 DOP。

不,它们不等价。

第一个表达式将 运行 在 Select 中并行使用。

第二个表达式将运行 工作在Select 一个线程中,以产生用于并行执行的项。您为使用第二个表达式所做的操作将 运行 并行,但这可能是微不足道的事情,无法从并行化中受益。

I was curious if the following two snippets are equivalent

不,他们不是。您之前的代码将 尝试 IEnumerable 进行分区以便并行执行。您后面的代码会将元素按顺序投射到您的 Select,并接收过滤后的 IEnumerable。只有 AsParallel 之后的内容才会 运行 并行。

请注意,LINQ-To-Entities 并不真正适用于 AsParallel。通常,它会导致您的代码 运行 比顺序慢。此外,DbContext 不是线程安全的。该代码可能会造成更多伤害而不是好处。

你可以做的是首先查询数据库,一旦数据在内存中,使用AsParallel

My desired behavior is for the DB call to be made synchronously, get a List back, and operate upon the list in parallel (make a bunch of web service calls on the List in parallel)

如果您想通过返回的数据进行多个 Web 服务调用,您可以利用现有的用于发出此类请求的自然异步 API。例如,如果您正在查询一个 HTTP 端点,您可以利用 HttpClient 并将其与 async-await 结合使用,并同时执行查询,而无需任何额外的线程。