[PLINQ]合併模式

PLINQ  合併模式

PLINQ介紹有提到PLINQ執行方式,會先將內容給分配不同的執行緒執行,等到跑foreach、ToArray()、ToList()的時候,會把結果merge回原本主要的執行緒上。

在merger回主執行緒上之前,PLINQ會預設建立buffer儲存部分結果,當buffer滿的時候,yield回傳結果。   而PLINQ有提供方法,可以設定buffer的機制。

 

Auto Buffered:

預設行為,PLINQ會自行選擇buffer Size,當buffer滿的時候,會將緩衝區內容一次產生至耗用端執行。

var data = Enumerable.Range(0, 10)                
.AsParallel()
.Select(x => 
{
    Thread.Sleep(1000);
    return x;
});

Stopwatch sw = Stopwatch.StartNew();

foreach (var item in data)
{
    Console.WriteLine("Value: {0}, Time: {1}", item, sw.ElapsedMilliseconds);
}

可以清楚看到20xx毫秒的時候,就是第一次buffer滿的時候輸出,接下就是等第二次buffer滿的時候,將剩下的值輸出,時間是30xx毫秒。

 

FullyBuffered:

會先將整個查詢輸出都放在緩衝區中,然後才產生任何項目。

var data = Enumerable.Range(0, 10)                
.AsParallel()
.WithMergeOptions(ParallelMergeOptions.FullyBuffered)
.Select(x => 
{
    Thread.Sleep(1000);
    return x;
});

Stopwatch sw = Stopwatch.StartNew();

foreach (var item in data)
{
    Console.WriteLine("Value: {0}, Time: {1}", item, sw.ElapsedMilliseconds);
}

只要加上 WithMergeOptions(ParallelMergeOptions.FullyBuffered) 設定,就可以強制PLINQ將所有輸出結果存在buffer裡面,然後一次輸出。

 

Not Buffered :

讓每個執行緒中處理的每個項目在產生後立即回傳。 如果查詢中出現AsOrdered,則會保留來源項目的順序。

var data = Enumerable.Range(0, 10)                
.AsParallel()
.WithMergeOptions(ParallelMergeOptions.NotBuffered)
.Select(x => 
{
    Thread.Sleep(1000);
    return x;
});

Stopwatch sw = Stopwatch.StartNew();

foreach (var item in data)
{
    Console.WriteLine("Value: {0}, Time: {1}", item, sw.ElapsedMilliseconds);
}

設定WithMergeOptions(ParallelMergeOptions.NotBuffered)就是指定PLINQ沒有buffer。從結果可以看出來,有三個執行緒,執行完就把結果拋出來。

 

另外並不是所有的運算子都可以使用此設定,如下圖示

支援合併模式

無支援合併模式

 

 

 

一天一分享,身體好健康。

該追究的不是過去的原因,而是現在的目的。