天天看點

并行循環

上次我們講到了集合。說到集合,那往往少不了循環。今天我們說下什麼是并行循環

Parallel.For,Paraller.Foreach 

(System.Threading.Tasks)

相信大家對此都不陌生。

long sum = 0;

Parallel.For(0, MaxValue, (i) =>

{

Interlocked.Add(ref sum, (long)Math.Sqrt(i));

values.Add(i);

});

也可以Paraller.Foreach.

中斷循環:

如果需要中斷循環,可以給循環的委托傳入一個ParallelLoopState對象,中止循環。有兩個方法。

Break,Stop;差別是什麼呢?

1:Break---告訴循環不要執行大于目前疊代次數的任何疊代。啥意思呢。就是大于i 的都會停止運作,小于i的依然會執行。注意:可能會有多個循環疊代發起Break調用,要看代碼邏輯了。

2:Stop:----停止任何疊代。

 問題調整

 ~對了。在使用并行循環的時候,要確定每次疊代的工作量要明顯大于同步共享狀态的開銷。如果你把循環的時間都耗在阻塞共享的循環變量上,那并行執行也就沒意義了。是以每次疊代都進行局部通路,

~并行循環還有另一個問題,就是委托。每次都會生成一個委托,如果每次疊代完成的工作還不如生成委托的開銷大。那就是殺雞用牛刀。大材小用。

說下委托的開銷吧。委托的開銷分為兩種:構造開銷和調用開銷,調用和普通方法調用差不多。構造開銷就很大。你應該隻做一次構造,并把對象緩存起來。把委托定義在循環外。

上面的問題怎麼解決呢?

用Partitioner類,它會把需要的疊代的區間分拆存入Tuple對象種。

public static void Main()

{

Stopwatch watch=new Stopwatch();

const int MaxValue=10000000;

long sum=0;

//普通循環

watch.Restart();

sum=0;

Parallel.For(0,MaxValue,(i)=>{

Interlocked.Add(ref sum,(long)Math.Sqrt(i));

});

watch.Stop();

Console.WriteLine("Parallel.For:{0}",watch.Elapsed);

//分區的For循環

var partitioner=Partitioner.Create(0,MaxValue);

Parallel.ForEach(partitioner,(range)=>{

long partialSum=0;

for(int i=range.Item1;i<range.Item2;i++)

{

partialSum+=(long)Math.Sqrt(i);

}

Interlocked.Add(ref sum,partialSum);

Console.WriteLine("Partitioned Parallel.For:{0}",watch.Elapsed);

}

并行循環

 我的電腦上執行的結果。

上面分區規則是靜态的,隻要疊代區間劃分完畢,每個區間都運作一個委托。其中有一個提前完成,也不會嘗試重新分區。

繼續閱讀