我正在读一本有关并行编程的书,它说在不使用锁的情况下将元素添加到列表中并不是线程节省,因为结果将不可预测。例如,如果我们必须添加80万个元素,那么最终结果将少于80万个元素。
现在我想知道从列表中读取元素是否是线程保存。例如,假设我有一个列表BlackListedNumbers
List<int> BlackListedNumbers = new List<int> {10, 50 ....... n};
//lets say there is 500 000 elements in the list
还有一个包含10000000数字的列表
Numbers
,显然我将使用parallel.Foreach完成此任务,我想要的是Final
列表,其中包含Numbers
列表中所有不在BlackListedNumbers
列表中的数字List<int> finalList = new List<int>();
Parallel.ForEach(Numbrs,
num =>
{
if (!blackListedNumbrs.Contains(num))
{
lock (finalList)
{
finalList.Add(num);
}
}
});
我知道这不是完成此任务的最有效方法,但我只是想说明问题。
所以我的问题是:从列表
blackListedNumbrs
读取结果是否保存线程,我将获得100%准确的结果吗? 最佳答案
从MSDN:
只要不修改集合,List<T>
就可以同时支持多个阅读器。
因此,如果您从不修改列表,就可以了。
请注意,使用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如评论中所述,我没有任何文档来支持此操作。但是从集合中读取并不需要修改任何共享状态,因此至少有意义。