2014-07-08 32 views
0

這是我的代碼:爲什麼我不能在Parallel.For或Parallel.Foreach上使用List.Add()?

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); 
}); 

我想要做的是,給我的學生名單。將其轉換爲學生模型,獲取學生姓名(因爲一個學生有很多姓名),然後我將姓名添加到姓名列表中,這是因爲可能以後我需要同名學生並做一些事情..... finally add學生到學生模型列表。

問題發生在:

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

這個地方總是在發生:System.IndexOutOfRangeException

我已經改變Paralle.Foreach到的Parallel.For,並更改的foreach爲,但沒有什麼變化。 我必須使用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列表時,它仍然拋出異常............

我也試用併發袋<>,但速度很慢....我可以別拿了.....

I請有任何好的方法來處理它。非常感謝你!

UPDATE:

什麼我不明白的是:爲什麼我不能添加一些東西在Parallel.Foreach列表。我認爲Parallel.Foreach將使用很多線程,但事件使用多線程添加對它沒有任何問題。

線程1添加和線程2添加沒有任何關係....爲什麼發生這種異常?

+0

'我也嘗試使用ConcurrentBag <>,但速度很慢....我不能接受它'然後寫一些比* ConcurrentBag *更好的可以同步訪問的東西。 – EZI

+0

不確定你要綁定什麼,但必須要比STUDENT_NAMES.Where(x => x.SearchWords == tempWords).FirstOrDefault()更有效。使用哈希集。 – Paparazzi

回答

11

List不適用於從多個線程訪問。這樣做並不安全。你可能遇到各種各樣的問題,從索引例外,增加丟失,重複,其他類型的錯誤,真的只是任何事情。

我也嘗試使用ConcurrentBag <>,但速度很慢....我不能把它.....

性能是無關緊要的,當只有兩個選項之一實際上有效。你可以讓代碼工作正常,並且只要需要,或者你可以讓代碼不起作用,並且錯誤的速度有多快,這是無關緊要的。

當然你還有其他的選擇,例如尋找重新設計你的程序的方法,使用本質上更有效的算法,而不是試圖做一些非常低效的事情,而只是爲了掩蓋事實。您目前在列表中執行班輪搜索以找到匹配項的事實是對於另一個集合中的每個項目而言是相當差的設計;您應該使用可以更有效地搜索的集合,例如HashSet。儘管不知道問題的細節,但我們不可能說應用程序的適當設計應該是什麼。

+0

每一個,如果你在Parallel.Foreach上有XX.Add(),你只需要將XX類型改爲從列表中進行hashset。問題將得到解決。謝謝@Servy。 – qakmak

+1

@qakmak不,它當然是*不*解決。 'HashSet'根本不是被設計成可以同時從多個線程中操作,並且這樣做會導致各種討厭的行爲,就像'List'一樣。你在一些測試中沒有注意到問題並不意味着沒有任何問題,即使沒有任何問題,也不表示未來不會有任何問題。 – Servy

+0

我覺得在發生索引問題之前因爲列表使用索引排序,那麼當某個線程添加一些對象也是另一個線程添加一些對象的時候,但HasSet不使用索引排序,所以我想問題解決了。因爲我只需要將對象添加到HasSet中使用Parallel.Foreach,就是這樣。 – qakmak

相關問題