2012-11-30 83 views
0

如果我有一個IEnumerable(列表)以下順序:如何PLINQ訂單輸入

1 - 2 - 3 - 4 - 5

,如果我上運行PLINQ查詢此說:

list.AsParallel().AsOrdered().WithDegreeOfParallelism(10).Select(
       s => SomeDelegateFunction(s)).AsSequential().ToList(); 

對於上述查詢,我​​在我的日誌記錄(內部委託函數)中看到它使用多個線程,但不維護列表的處理順序。 然而,對於下面的查詢我確實維持序列,但是使用單個線程來執行的全部操作:

list.AsParallel().AsOrdered().WithDegreeOfParallelism(10).AsSequential().Select(
       s => SomeDelegateFunction(s)).ToList(); 

兩個查詢之間的差是「AsSequential()」中的第二查詢,該問題,我當時我使用AsSequential():

1 - 爲什麼它不使用多線程?它可能已經破裂的工作爲:

1 - 2 (Give it to thread 1) 
3 - 4 - 5 (Give it to thread 2) 

相反,它所做的1 - 2 - 3 - 4 - 5(按順序),但它確實在單個線程 - 爲什麼?

基本上我需要處理我的列表在ORDER它作爲輸入,但在多個線程。

任何想法?

回答

4

基本上我需要處理我的列表在ORDER它作爲輸入,但在多個線程進入。

這些是互斥的要求。你可以做一個或另一個,但從來都沒有。

如果您不在乎訂單處理的順序,您只是想確保您的最終結果是這些對象按照他們第一次進來的順序排列,因爲您可以這樣做:

var list = new List<int> { 1, 2, 3, 4, 5 }; 

Parallel.For(0, list.Count, i => 
{ 
    list[i] = Process(i); 
}); 

如果你喜歡PLINQ在Parallel.For你可以做這樣的事情:

Enumerable.Range(0, list.Count) 
    .AsParallel() 
    .WithDegreeOfParallelism(10) 
    .ForAll(i => 
    { 
     list[i] = Process(i); 
    }); 
+0

嗯......理論上,工作分工可能已經按順序完成,然後並行工作 - 正確嗎? –

+0

@MurtazaMandvi在我引用你的陳述中明確指出,他們需要按照他們進來的順序進行處理。這使問題不能並行解決。如果您希望它以任何順序處理它們,但確保完成後最終結果將以與首次收到時相同的順序返回,那麼這是可能的,但這不是您要求的。 – Servy

+0

你的代碼可以工作,但我認爲使用'AsOrdered()'是一個更清潔的選擇:你不必處理索引,結果將是相同的。 – svick

0

一個多線程的生產者 - 消費者模式將允許您以確保項目在同一順序處理,同時讓項目同時處理。正如Servy所說,如果您需要確保在下一個項目的處理開始之前完成每個項目的處理,那麼您的運氣不好。

在生產者 - 消費者模式中,爲了維護順序,可以使用線程安全隊列。一個或多個生產者線程排列要處理的項目;在這種情況下,您將有一個生產者將列表中的項目順序傳遞給隊列。然後多個消費者線程可以將項目出隊,這將按順序排列。

有關更多信息,請參閱http://en.wikipedia.org/wiki/Producer-consumer_problem

1

回答你的第一個問題

爲何不使用多線程?

AsSequential()的作用與AsParallel()的作用完全相反。 AsParallel()在有序序列IEnumerable<T>上創建了一個ParallelQuery<T>以允許在多個線程中並行執行。 AsSequential()用於將並行執行的結果合併到一個枚舉回到調用者線程中。

回答你的第二個問題

它可能已經破裂的工作爲:

1 - 2 (Give it to thread 1) 
3 - 4 - 5 (Give it to thread 2) 

是的,它可以,但在這個並行執行的情況下,序列3個大概會處理在1之前,它不會是順序執行。

不過,您可以明確控制PLINQ如何將序列分解爲多個分區。因此,您可以控制自己的數據如何在多個線程之間分配見Custom Partitioners for PLINQ