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。從結果可以看出來,有三個執行緒,執行完就把結果拋出來。
另外並不是所有的運算子都可以使用此設定,如下圖示
支援合併模式
無支援合併模式
一天一分享,身體好健康。
該追究的不是過去的原因,而是現在的目的。