Parallel.ForEach返回不一致的结果

时间:2016-04-20 13:27:21

标签: c# parallel-processing parallel.foreach

我有一个方法,它读取一个文本文件,每行包含一个int值,为了使读取更快,我使用Parallel.ForEach,但我所看到的行为是意外的,我在文件中有800行但是当我运行这个方法时,每次它返回不同的HashSet计数时,我在搜索后读到的是Parallel.ForEach生成多个线程并且当所有线程完成其工作时它返回结果,但是我的代码执行矛盾,或者我错过了一些重要的东西?

这是我的方法:

private HashSet<int> GetKeyItemsProcessed()
{
   HashSet<int> keyItems = new HashSet<int>();

   if (!File.Exists(TrackingFilePath))
     return keyItems;

     // normal foreach works fine

     //foreach(var keyItem in File.ReadAllLines(TrackingFilePath))
     //{
     //    keyItems.Add(int.Parse(keyItem));
     //}


     // this does not return right number of hashset rows
     Parallel.ForEach(File.ReadAllLines(TrackingFilePath).AsParallel(), keyItem =>
     {
         keyItems.Add(int.Parse(keyItem));
     });


    return keyItems;

}

1 个答案:

答案 0 :(得分:5)

HashSet.Add不是线程安全的。

来自MSDN

  

此类型的任何公共静态(在Visual Basic中为Shared)成员都是   线程安全。任何实例成员都不能保证是线程   安全

多线程时序的不可预测性可能并且似乎正在引发问题。

您可以将访问包装在同步构造中,这有时比并发集合更快,但在某些情况下可能无法加快速度。正如其他人所提到的,另一种选择是使用线程安全集合,如ConcurrenDictionaryConcurrentQueue,尽管这些可能会产生额外的内存开销。

请务必根据时间对任何结果进行基准测试。单线程访问的原始功能有时比处理线程开销更快。编写此代码可能不值得。

最后一句话是,HashSet单独,没有同步,对多线程操作来说是不可接受的。