为什么我不能在Parallel.For或Parallel.Foreach上使用List.Add()?

时间:2014-07-08 20:52:03

标签: c# .net linq plinq

这是我的代码:

Parallel.ForEach(Students, item =>
{
   StudentModel studentModel = new StudentModel(item);

   // Maybe he/she has alot of name
   foreach (var words in studentModel.StudentNames.Split(','))
   {
        if (string.IsNullOrWhiteSpace(words))
                return;

        string tempWords = words.Trim();
        // add it to student names list
        STUDENT_NAMES.Where(x => x.SearchWords == tempWords).FirstOrDefault().student.Add(studentModel);


     }
     // add it to student list
     STUDENT_MODELS.Add(studentModel);
});

我想做的是,我得到学生名单。将它转换为学生模型,获取学生姓名(因为一个学生有很多名字),然后我将名字添加到名单,这是因为可能以后我需要得到同名的学生并做一些事..... 最后将学生添加到学生模型列表中。

问题发生在:

STUDENT_NAMES.Where(x => x.SearchWords == tempWords).FirstOrDefault().student.Add(studentModel);

这个地方总是发生: System.IndexOutOfRangeException

我已经将Paralle.Foreach更改为Parallel.For,并将foreach更改为for,但没有任何更改。 我必须使用Parallel因为学生数量大约为100000,如果我只使用foreach替换Parallel.Foreach,则需要160+秒,如果我锁定那个地方.....还是慢......如果使用Parallel。 Foreach,它将使用20秒左右,但我无法处理异常。

我已经尝试过这个替换它:

StudentNames name = STUDENT_NAMES.Where(x => x.SearchWords == tempWords).FirstOrDefault();
if (null != name)
   name.student.Add(StudentModel);

但问题有时仍会发生........ 如果我只是尝试...抓住并忽略它,那么当我以后访问STUDENT_NAMES列表时,它仍会抛出该异常............

我也尝试使用 ConcurrentBag<> ,但速度很慢......我不能接受它.....

有没有好办法处理它。非常感谢你!

更新

我无法理解的是:为什么我不能在Parallel.Foreach的列表中添加一些东西。我认为Parallel.Foreach将使用很多线程,但事件使用多个线程添加对它没有任何问题。

线程1添加和线程2添加没有任何关系....为什么会发生该异常?

1 个答案:

答案 0 :(得分:11)

List不适用于从多个线程访问。这样做是不安全的。您可以遇到各种各样的问题,包括索引异常,添加丢失,重复,其他类型的错误,几乎任何问题。

  

我也尝试使用ConcurrentBag<> ,但速度很慢......我不能接受它......

当两个选项中只有一个实际有效时,性能无关紧要。你可以让代码正常工作并花费尽可能长的代码,或者你可以拥有不起作用的代码,以及它与错误的速度有多快这是无关紧要的。

当然,您还有其他选择,例如查看重新设计程序的方法,以使用本质上更有效的算法,而不是尝试做一些非常低效的事情,而只是将其并行化以隐藏这一事实。您目前正在列表中执行线性搜索,以便为另一个集合中的每个项目找到匹配的项目这一事实是一个相当糟糕的设计;您应该使用可以更有效搜索的集合,例如HashSet。虽然不知道问题的细节,但我们无法说明应用程序的正确设计应该是什么。