C# Parallel.ForEach返回不一致的结果

C# Parallel.ForEach返回不一致的结果,c#,parallel-processing,parallel.foreach,C#,Parallel Processing,Parallel.foreach,我有一个方法,可以读取每行包含int值的文本文件,为了加快读取速度,我使用了Parallel.ForEach,但我看到的行为出乎意料,我在文件中有800行,但当我运行此方法时,每次它返回不同的哈希集计数,我在搜索后读到的是并行的。ForEach生成多个线程,当所有线程都完成了它们的工作时,它返回结果,但是我的代码执行不一致,或者我缺少了一些重要的东西 以下是我的方法: private HashSet<int> GetKeyItemsProcessed() { HashSet&l

我有一个方法,可以读取每行包含int值的文本文件,为了加快读取速度,我使用了
Parallel.ForEach
,但我看到的行为出乎意料,我在文件中有800行,但当我运行此方法时,每次它返回不同的哈希集计数,我在搜索后读到的是并行的。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;

}
private HashSet GetKeyItemsProcessed()
{
HashSet-keyItems=新HashSet();
如果(!File.Exists(TrackingFilePath))
返回关键项目;
//正常的foreach工作正常
//foreach(File.ReadAllLines(TrackingFilePath)中的var keyItem)
//{
//添加(int.Parse(keyItem));
//}
//这不会返回正确数量的hashset行
Parallel.ForEach(File.ReadAllLines(TrackingFilePath).aspallel(),keyItem=>
{
添加(int.Parse(keyItem));
});
返回关键项目;
}

哈希集。Add
不是线程安全的

发件人:

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

多线程计时的不可预测性可能(而且似乎)会导致问题

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

一定要在时间方面对你得到的任何结果进行基准测试。单线程访问的原始能力有时比处理线程开销更快。执行此代码可能根本不值得


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

HashSet.Add
不是线程安全的

发件人:

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

多线程计时的不可预测性可能(而且似乎)会导致问题

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

一定要在时间方面对你得到的任何结果进行基准测试。单线程访问的原始能力有时比处理线程开销更快。执行此代码可能根本不值得


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

我敢打赌这不是
C
。修改
HashSet
。为什么不使用ConcurrendDictionary或ConcurrentQueue之类的Concurrent集合呢?我使用的是
HashSet
以获得更好的性能,您提到的上述集合在读取时是否性能良好?您的瓶颈几乎肯定是磁盘限制,而不是CPU限制。因此,并行运行并没有多大意义。此外,除非您使用它进行查找,否则
列表
可能更好(不清楚“读取”集合的含义)。您的
.aspallel()
只会造成额外的开销,不会给您带来任何好处,
Parallel.ForEach
不支持并行枚举,因此将再次序列化它。我敢打赌这不是
C
。修改
哈希集
。为什么不使用ConcurrendDictionary或ConcurrentQueue之类的Concurrent集合呢?我使用的是
HashSet
以获得更好的性能,您提到的上述集合在读取时是否性能良好?您的瓶颈几乎肯定是磁盘限制,而不是CPU限制。因此,并行运行并没有多大意义。此外,除非您使用它进行查找,否则
列表
可能更好(不清楚“读取”集合的含义)。您的
.aspallel()
只会造成额外的开销,不会给您带来任何好处,
Parallel.ForEach
不支持并行枚举,因此将再次序列化它。同步集合上的
可能比使用并发集合更快。这取决于争论的程度。事实上,我们应该更进一步:
Parallel.ForEach
在OP的场景中并不一定更快。简单地按顺序读取行可以轻松地胜过并行开销。(当然,这超出了原始问题的范围,它只是问为什么结果不一致。)@如果文件太大,磁盘I/O并行性中的JeroenMostert将不会有帮助?ConcurrentDictionary工作得很好,但我认为如果在磁盘I/O中,它将是开销,而不是性能更好,那么我不会使用并行loop@EhsanSajjad:@Jeroemostert因为你这么说,因此,确认您是否测试了同步集合上的
比使用并发集合更快。这取决于争论的程度。事实上,我们应该更进一步:
Parallel.ForEach
在OP的场景中并不一定更快。简单地按顺序读取行可以轻松地胜过并行开销。(当然,这超出了原始问题的范围,它只是问为什么r