使用列表的 C# 并行编程 - 读取线程安全吗?

标签 c# list parallel-processing

我正在阅读一本关于并行编程的书,它说在不使用锁的情况下将元素添加到列表不是线程保存,因为结果将是不可预测的。例如,如果我们必须向列表中添加 800 000 个元素,则最终结果将少于 800 000 个元素。

现在我想知道是否线程保存到列表中的读取元素。例如,假设我有一个列表 BlackListedNumbers

List<int> BlackListedNumbers = new List<int> {10, 50 ....... n}; 
//lets say there is 500 000 elements in the list

和另一个列表 Numbers 包含 10 000 000 个数字,显然我将使用 parallel.Foreach 来完成这个任务,我想要的是 Final 包含所有数字的列表不在 BlackListedNumbers 列表中的 Numbers

List<int> finalList = new List<int>();
Parallel.ForEach(Numbrs, 
  num =>
    {
      if (!blackListedNumbrs.Contains(num))
      {
        lock (finalList)
        {
          finalList.Add(num);
        }
      }
  });

我知道这不是完成此任务的最有效方法,但我只是想说明问题。

所以我的问题是:从 List blackListedNubrs 读取结果是否需要线程保存,我会得到 100% 准确的结果吗?

最佳答案

来自 MSDN :

A List<T> can support multiple readers concurrently, as long as the collection is not modified.

因此,如果您从不修改列表,应该没问题。

请注意,使用 HashSet<int>会更有效率 - 和 HashSet<T>还支持多个阅读器1。您可以使用 Parallel LINQ 使您的查询更甜美并且几乎可以肯定更高效:

// If you want duplicates in Numbers to still come up as duplicates in the result
HashSet<int> blacklistedSet = new HashSet<int>(blackListedNumbers);
List<int> finalList = Numbers.AsParallel()
                             .Where(x => !blacklistedSet.Contains(x))
                             .ToList();

// Or if you just want a set-based operation:

List<int> finalList = Numbers.AsParallel()
                             .Except(blacklistedSet)
                             .ToList();

更好,而且不需要锁定 :)


1 如评论中所述,我没有任何文档来支持这一点。但是从集合中读取不需要修改任何共享状态,所以它至少是有意义的...

关于使用列表的 C# 并行编程 - 读取线程安全吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6769276/

相关文章:

c# - 事件计时器在 .NET 中延迟,而不是在 Mono 中。这是一个错误吗?

r - 有没有办法跟踪并行随机森林构建过程中的进度?

c# - ManualResetEventSlim.Set() 并不总是解锁任务内的等待

C#相当于Java的Thread.setDaemon?

c# - 输入字符串错误

java - 如何使用 Java 8 Lambdas 将对象列表转换为 Map<Object, Object>

c - 删除链表的第一个节点

java - 数组/列表问题

c - 努西诺夫平行

multithreading - Chapel、语言环境和多核多处理器机器