Parallel.ForEach返回不一致的结果

Ehs*_*jad 0 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;

}
Run Code Online (Sandbox Code Playgroud)

Bra*_*ner 5

HashSet.Add 不是线程安全的.

来自MSDN:

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

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

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

请务必根据时间对任何结果进行基准测试.单线程访问的原始功能有时比处理线程开销更快.完全破坏这段代码可能不值得.

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