c# - 使用 Parallel.ForEach() 的 yield return 的线程安全

标签 c# task-parallel-library ienumerable yield-return parallel.foreach

考虑以下代码示例,它创建一个可枚举的整数集合并并行处理它:

using System.Collections.Generic;
using System.Threading.Tasks;

public class Program
{
    public static void Main()
    {
        Parallel.ForEach(CreateItems(100), item => ProcessItem(item));
    }

    private static IEnumerable<int> CreateItems(int count)
    {
        for (int i = 0; i < count; i++)
        {
            yield return i;
        }
    }

    private static void ProcessItem(int item)
    {
        // Do something
    }
}

是否保证 Parallel.ForEach() 生成的工作线程每个都获得不同的项目,或者是否需要一些围绕 i 的递增和返回的锁定机制?

最佳答案

Parallel.ForEach<TSource> , 当 TSource是一个 IEnumerable<T> , 为 IEnumerable<T> 创建一个分区器它包含自己的内部锁定机制,因此您无需在迭代器中实现任何线程安全。

每当工作线程请求一大块项目时,分区程序将创建一个内部枚举器,它:

  1. 获取共享锁
  2. 遍历源(从它离开的地方)以检索项目 block ,将项目保存在私有(private)数组中
  3. 释放锁以便其他 block 请求可以得到满足。
  4. 从其私有(private)数组为工作线程提供服务。

如您所见,运行 IEnumerable<T>出于分区的目的,分区是顺序的(通过共享锁访问),并且分区是并行处理的。

关于c# - 使用 Parallel.ForEach() 的 yield return 的线程安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17021779/

相关文章:

c# - 迭代 IEnumerable,特殊套管最后一个元素

c# - 在数组中查找多个索引

c# - 使用 TTS Android 保存更大的文件

c# - 并行执行网络服务调用

c# - IEnumerable 是否需要使用 foreach 循环?

c# - 为什么将单个元素与 IEnumerable 进行比较不是编译错误

c# - 在线程之间同步 VBO 的最佳方式

c# - 如何在不重新部署 webApp 的情况下通过 TFS 删除 WebServer 中的特定文件(未使用的文件)。 C#、.Net

c# - 如何在使用 Reactive Extensions 测试 Observables 时为 Task.Run 使用虚拟时间

entity-framework - Entity Framework 取消长时间运行的查询