2011-04-15 43 views
4

我很少懷疑在多線程應用程序中如何共享IEnumerableIQueryable在多線程應用程序中共享IEnumerable <T>和IQueryable <T>

考慮這段代碼片段。

ObservableCollection<SessionFile> files = /* some code */ 
IEnumerable<Pattern> allFilePatterns= /*some query */ 

foreach (Pattern pattern in allFilePatterns) 
{ 
    string iclFilePath = Path.Combine(pattern.Location, pattern.Filename); 
    SessionFile sfile = new SessionFile(iclFilePath, pattern.AnalysisDate); 

    SomeDelegate invoker = new SomeDelegate(sfile.SomeHandler); 
    invoker.BeginInvoke(allFilePatterns, null, null); 

    files.Add(sfile); 
} 

正如你所看到的,我使用BeginInvoke()相同例如allFilePatterns傳遞給每個處理程序稱爲sfile.SomeHandler

假設在SomeHandler,我重複allFilePatternsforeach循環,這樣的事情:

void SomeHandler(IEnumerable<Pattern> allFilePatterns) 
{ 
    foreach(Pattern pattern in allFilePatterns) 
    { 
      //some code 
    } 
} 

現在我的疑問是:自BeginInvoke()是異步的,這意味着在所有的所有SomeHandler所有foreach文件將並行執行(每個文件在其自己的線程中),IEnumerable的共享實例是否按預期方式枚舉?這是一個正確的方法嗎?我可以在多個線程中共享相同的IEnumerable的實例,並且並行枚舉它嗎?

如果我在上面的代碼中使用IQueryable而不是IEnumerable會怎麼樣?我應該知道的任何副作用?

如果它不是線程安全的,那麼我應該使用什麼?

請注意,我正在使用IQueryable進行數據庫查詢,因爲我不想從數據庫中提取所有數據。因此,我想盡可能避免IQueryable.ToList()

回答

4

這取決於實施。 IEnumerable<T>的一些實現也實現了IEnumerator<T>,並從GetEnumerator()返回自己。在這種情況下,它顯然不是線程安全的...

至於IQueryable<T>,這也取決於實施。例如,Entity Framework上下文不是線程安全的,只能在創建它們的線程上正常工作。

因此,對於這個問題沒有獨特的答案......它可能適用於某些實現,而不適用於其他實現。

1

我會ToList()你的enumerable作爲參數傳遞給委託時,實際創建一個新的線程來處理和避免問題。

但是,我想知道爲什麼你需要有可枚舉的每個元素N次(有效N^2)?這聽起來效率低下。

編輯:更新我的意圖

+0

這仍然取決於SessionFile和Pattern的線程安全性 – sehe 2011-04-15 12:14:04

0

嗯,有一件事你可以做的,如果有那不是線程安全的(如實體框架查詢)一個IQueryable工作是枚舉會導致一個線程,但會根據需要將結果傳遞給新線程。

然後,如果IQueryable/IEnumerable是線程安全的,則無關緊要。

相關問題