2013-03-20 47 views
3

的IEnumerable 結果我瞭解LINQ延遲執行如下解釋: What are the benefits of a Deferred Execution in LINQ? 從方法和延遲執行

然而,延遲執行可導致尤其是在多線程方案如錯誤。在鎖之外的共享集合上執行評估。當一個返回延遲評估的方法嵌套多個方法層時,它可能會非常難以記住或保持跟蹤,以便適當鎖定。

忽略像無限序列(如Fibonacci)這樣的特殊情況,並且假設集合的過濾被認爲是完全的(即消費者不太可能會進一步過濾結果),那麼會被認爲是「最好的方法「從一個方法返回一個IEnumerable集合時 - 是否應該評估或推遲?

注意:「最佳方法」可以根據其他度量的效率/代碼安全性來定義,只需在您的響應中進行驗證即可。我想知道社區如何做到這一點。

後續問題:在方法名稱中明確聲明結果是否被評估或推遲是否有意義?

回答

2

你寫的大部分代碼不是多線程的。事實上,只有三個原因,我能想到,當你想急切地評估一個枚舉的:

  1. 你需要它在多線程環境。你應該把它變成一個列表或數組。
  2. 你想隨機訪問可枚舉。你應該把它變成一個列表或數組。
  3. 您想控制何時進行評估(例如,如果價格昂貴)。

在其他時間,你應該讓它使用延遲執行。這將評估推遲到實際需要的時間點,並且可能會更快,具體取決於您應用的過濾器。例如,bigquery.First()可能會比bigquery.ToArray().First()更快。你能否確定用戶完成了過濾?

另外,運行時will optimize certain LINQ queries。這個例子是從Jon Skeet的文章LINQ To Objects and the performance of nested "Where" calls採取:

// Normal LINQ query 
var query = list.Where(x => Condition1(x)) 
       .Where(x => Condition2(x)) 
       .Select(x => Projection1(x)) 
       .Select(y => Projection2(y)); 

// After optimization 
var query = list.WhereSelect(x => Condition1(x) && Condition2(x), 
          x => Projection2(Projection1(x)); 

順便說一句,你的方法應該返回最具體出現的類型,他們可以。例如,處理T[]數組或List<T>列表的方法在內部通常不應只返回IEnumerable<T>。如果您希望結果是不可變的,請將它換成ReadOnlyCollection<T>

+0

在其他項目中編寫用於最大程度重用的類時,如果消費者正在多線程場景中運行,則不會先驗地知道該類。多線程環境中的非線程安全類很糟糕。所以你的觀點1.似乎表明所有的方法都應該進行急切的評估? – JohnC 2013-03-20 16:34:03

+0

@JohnC我會爭辯說,一個可枚舉的_knows_的使用者,默認情況下它是_not_線程安全的。在大多數情況下,這不是問題。如果這是一個問題,確保它是線程安全的是消費者的責任。例如通過調用它上面的「ToArray」。如果底層集合已經是一個數組,則什麼都不會發生。否則,在這一點上進行評估。 – Virtlink 2013-03-20 16:36:41

+0

參考你的bigquery的例子。First()比bigquery.ToArray()。First()更快,請注意,我在我的問題中聲明「假設集合的過濾被認爲是完整的(即消費者不太可能會進一步過濾結果) 」。在你的例子中,數組被進一步過濾了第一個元素;不完全是我所要求的場景。 – JohnC 2013-03-20 16:36:47