當查詢以平行方式執行時,PLINQ 會分割來源序列,讓多個線程可以同時在不同的部分上運作,通常是在不同的線程上。 例如,若要在單個執行緒中處理結果(例如 Visual Basic 中的 foreach 迴圈),則必須將每個執行緒的結果合併回到一個序列中。 PLINQ 執行的合併類型取決於查詢中存在的運算符。 例如,對結果施加新順序的運算元必須緩衝來自所有線程的所有元素。 從消費者線程(也就是應用程式使用者)的觀點來看,完全緩衝的查詢可能會在產生第一個結果之前執行一段顯著的時間。 根據預設,其他運算符會部分緩衝處理;它們會以批次方式產生其結果。 預設情況下,運算符 ForAll 不會緩衝處理。 它會立即從所有線程產生所有元素。
使用 WithMergeOptions 方法,如下列範例所示,您可以提供提示給 PLINQ,指出要執行的合併類型。
var scanLines = from n in nums.AsParallel()
.WithMergeOptions(ParallelMergeOptions.NotBuffered)
where n % 2 == 0
select ExpensiveFunc(n);
Dim scanlines = From n In nums.AsParallel().WithMergeOptions(ParallelMergeOptions.NotBuffered)
Where n Mod 2 = 0
Select ExpensiveFunc(n)
如需完整的範例,請參閱 如何:在 PLINQ 中指定合併選項。
如果特定查詢不支援要求的選項,則只會忽略選項。 在大部分情況下,您不需要指定 PLINQ 查詢的合併選項。 不過,在某些情況下,您可能會發現藉由測試和測量,查詢在非預設模式中具有最佳效能。 這個選項的常見用法是強制區塊合併運算符串流其結果,以提供更回應的使用者介面。
並行合併選項
列舉 ParallelMergeOptions 包含下列選項,這些選項會針對支援的查詢圖形指定在一個執行緒上取用結果時,查詢的最終輸出以何種方式產生:
Not Buffered選項 NotBuffered 會使每處理完的元素立即從各個線程中傳回。 此行為類似於將輸出「串流化」。 AsOrdered如果運算子存在於查詢中,
NotBuffered則保留來源元素的順序。 雖然NotBuffered只要有結果就開始產生結果,但產生所有結果的總時間可能仍然比使用其他合併選項之一還要長。Auto Buffered選項 AutoBuffered 會讓查詢將元素收集到緩衝區,然後定期將緩衝區內容一次產生給取用線程。 這類似於在「區塊」中產生源數據,並非採用
NotBuffered的「串流」行為。AutoBuffered可能需要比NotBuffered在取用線程上提供第一個元素的時間還要長。 緩衝區的大小和具體的調度行為無法設定,且可能會因查詢相關的各種因素而有所不同。FullyBuffered選項 FullyBuffered 會在產出任何元素之前緩衝整個查詢的輸出。 當您使用這個選項時,在消費線程中第一個元素可用之前可能需要更長的時間,但完整的結果仍有可能比使用其他選項更快產生。
支援合併選項的查詢運算符
下表列出支援所有合併選項模式的運算元,受限於指定的限制。
| 操作員 | 限制 |
|---|---|
| AsEnumerable | 沒有 |
| Cast | 沒有 |
| Concat | 只有陣列或清單來源的非排序查詢。 |
| DefaultIfEmpty | 沒有 |
| OfType | 沒有 |
| Reverse | 只有陣列或清單來源的非排序查詢。 |
| Select | 沒有 |
| SelectMany | 沒有 |
| Skip | 沒有 |
| Take | 沒有 |
| Where | 沒有 |
所有其他 PLINQ 查詢運算符可能會忽略使用者提供的合併選項。 某些查詢運算子,例如 Reverse 和 OrderBy,在產生並重新排序之前,無法產生任何元素。 因此,當在包含這類運算符ParallelMergeOptions的查詢中使用Reverse時,合併行為不會在查詢中套用,直至該運算符產生其結果為止。
某些運算子處理合併選項的能力取決於來源序列的類型,以及運算符是否 AsOrdered 在查詢中稍早使用。 ForAll 一律 NotBuffered 為 ,它會立即產生其元素。 OrderBy 總是 FullyBuffered;它必須排序整個清單才能輸出。