亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

看看Parallel中高度封裝的三個方法,Invoke,For和ForEach

2019-11-14 16:21:46
字體:
來源:轉載
供稿:網友

  說到.net中的并行編程,也許你的第一反應就是Task,確實Task是一個非常靈活的用于并行編程的一個專用類,不可否認越靈活的東西用起來就越

復雜,高度封裝的東西用起來很簡單,但是缺失了靈活性,這篇我們就看看這些好用但靈活性不高的幾個并行方法。

 

一:Invoke

  現在電子商務的網站都少不了訂單的流程,沒有訂單的話網站也就沒有存活的價值了,往往在訂單提交成功后,通常會有這兩個操作,第一個:發起

信用卡扣款,第二個:發送emial確認單,這兩個操作我們就可以在下單接口調用成功后,因為兩個方法是互不干擾的,所以就可以用invoke來玩玩了。

 1         static void Main(string[] args) 2         { 3             Parallel.Invoke(Credit, Email); 4  5             Console.Read(); 6         } 7  8         static void Credit() 9         {10             Console.WriteLine("******************  發起信用卡扣款中  ******************");11 12             Thread.Sleep(2000);13 14             Console.WriteLine("扣款成功!");15         }16 17         static void Email()18         {19             Console.WriteLine("******************  發送郵件確認單!*****************");20 21             Thread.Sleep(3000);22 23             Console.WriteLine("email發送成功!");24         }

 

 

  怎么樣,實現起來是不是很簡單,只要把你需要的方法塞給invoke就行了,不過在這個方法里面有一個重載參數需要注意下,

1  public static void Invoke(ParallelOptions parallelOptions, params Action[] actions);

 

有時候我們的線程可能會跑遍所有的內核,為了提高其他應用程序的穩定性,就要限制參與的內核,正好ParallelOptions提供了

MaxDegreeOfParallelism屬性。

 

好了,下面我們大概翻翻invoke里面的代碼實現,發現有幾個好玩的地方:

 

<1>: 當invoke中的方法超過10個話,我們發現它走了一個internal可見的ParallelForReplicatingTask的FCL內部專用類,而這個類是繼承自

   Task的,當方法少于10個的話,才會走常規的Task.

<2> 居然發現了一個裝exception 的ConcurrentQueue<Exception>隊列集合,多個異常入隊后,再包裝成AggregateException拋出來。

       比如:throw new AggregateException(exceptionQ);

<3> 我們發現,不管是超過10個還是小于10個,都是通過WaitAll來等待所有的執行,所以缺點就在這個地方,如果某一個方法執行時間太長

   不能退出,那么這個方法是不是會長期掛在這里不能出來,也就導致了主流程一直掛起,然后頁面就一直掛起,所以這個是一個非常危險

      的行為,如果我們用task中就可以在waitall中設置一個過期時間,但invoke卻沒法做到,所以在使用invoke的時候要慎重考慮。

  1     try  2     {  3         if (actionsCopy.Length > 10 || (parallelOptions.MaxDegreeOfParallelism != -1 && parallelOptions.MaxDegreeOfParallelism < actionsCopy.Length))  4         {  5             ConcurrentQueue<Exception> exceptionQ = null;  6             try  7             {  8                 int actionIndex = 0;  9                 ParallelForReplicatingTask parallelForReplicatingTask = new ParallelForReplicatingTask(parallelOptions, delegate 10                 { 11                     for (int l = Interlocked.Increment(ref actionIndex); l <= actionsCopy.Length; l = Interlocked.Increment(ref actionIndex)) 12                     { 13                         try 14                         { 15                             actionsCopy[l - 1](); 16                         } 17                         catch (Exception item) 18                         { 19                             LazyInitializer.EnsureInitialized<ConcurrentQueue<Exception>>(ref exceptionQ, () => new ConcurrentQueue<Exception>()); 20                             exceptionQ.Enqueue(item); 21                         } 22                         if (parallelOptions.CancellationToken.IsCancellationRequested) 23                         { 24                             throw new OperationCanceledException(parallelOptions.CancellationToken); 25                         } 26                     } 27                 }, TaskCreationOptions.None, InternalTaskOptions.SelfReplicating); 28                 parallelForReplicatingTask.RunSynchronously(parallelOptions.EffectiveTaskScheduler); 29                 parallelForReplicatingTask.Wait(); 30             } 31             catch (Exception ex2) 32             { 33                 LazyInitializer.EnsureInitialized<ConcurrentQueue<Exception>>(ref exceptionQ, () => new ConcurrentQueue<Exception>()); 34                 AggregateException ex = ex2 as AggregateException; 35                 if (ex != null) 36                 { 37                     using (IEnumerator<Exception> enumerator = ex.InnerExceptions.GetEnumerator()) 38                     { 39                         while (enumerator.MoveNext()) 40                         { 41                             Exception current = enumerator.Current; 42                             exceptionQ.Enqueue(current); 43                         } 44                         goto IL_264; 45                     } 46                 } 47                 exceptionQ.Enqueue(ex2); 48                 IL_264:; 49             } 50             if (exceptionQ != null && exceptionQ.Count > 0) 51             { 52                 Parallel.ThrowIfReducableToSingleOCE(exceptionQ, parallelOptions.CancellationToken); 53                 throw new AggregateException(exceptionQ); 54             } 55         } 56         else 57         { 58             Task[] array = new Task[actionsCopy.Length]; 59             if (parallelOptions.CancellationToken.IsCancellationRequested) 60             { 61                 throw new OperationCanceledException(parallelOptions.CancellationToken); 62             } 63             for (int j = 0; j < array.Length; j++) 64             { 65                 array[j] = Task.Factory.StartNew(actionsCopy[j], parallelOptions.CancellationToken, TaskCreationOptions.None, InternalTaskOptions.None, parallelOptions.EffectiveTaskScheduler); 66             } 67             try 68             { 69                 if (array.Length <= 4) 70                 { 71                     Task.FastWaitAll(array); 72                 } 73                 else 74                 { 75                     Task.WaitAll(array); 76                 } 77             } 78             catch (AggregateException ex3) 79             { 80                 Parallel.ThrowIfReducableToSingleOCE(ex3.InnerExceptions, parallelOptions.CancellationToken); 81                 throw; 82             } 83             finally 84             { 85                 for (int k = 0; k < array.Length; k++) 86                 { 87                     if (array[k].IsCompleted) 88                     { 89                         array[k].Dispose(); 90                     } 91                 } 92             } 93         } 94     } 95     finally 96     { 97         if (TplEtwPRovider.Log.IsEnabled()) 98         { 99             TplEtwProvider.Log.ParallelInvokeEnd((task != null) ? task.m_taskScheduler.Id : TaskScheduler.Current.Id, (task != null) ? task.Id : 0, forkJoinContextID);100         }101     }

 

二:For

   下面再看看Parallel.For,我們知道普通的For是一個串行操作,如果說你的for中每條流程都需要執行一個方法,并且這些方法可以并行操作且

比較耗時,那么為何不嘗試用Parallel.For呢,就比如下面的代碼。

 1 class Program 2     { 3         static void Main(string[] args) 4         { 5             List<Action> actions = new List<Action>() { Credit, Email }; 6  7             var result = Parallel.For(0, actions.Count, (i) => 8             { 9                 actions[i]();10             });11 12             Console.WriteLine("執行狀態:" + result.IsCompleted);13 14             Console.Read();15         }16 17         static void Credit()18         {19             Console.WriteLine("******************  發起信用卡扣款中  ******************");20 21             Thread.Sleep(2000);22 23             Console.WriteLine("扣款成功!");24         }25 26         static void Email()27         {28             Console.WriteLine("******************  發送郵件確認單!*****************");29 30             Thread.Sleep(3000);31 32             Console.WriteLine("email發送成功!");33         }34     }


下面我們再看看Parallel.For中的最簡單的重載和最復雜的重載:

1 public static ParallelLoopResult For(int fromInclusive, int toExclusive, Action<int> body);2 3 public static ParallelLoopResult For<TLocal>(int fromInclusive, int toExclusive, ParallelOptions parallelOptions, Func<TLocal> localInit, Func<int, ParallelLoopState, TLocal, TLocal> body, Action<TLocal> localFinally);4  

 

<1> 簡單的重載不必多說,很簡單,我上面的例子也演示了。

<2> 最復雜的這種重載提供了一個AOP的功能,在每一個body的action執行之前會先執行localInit這個action,在body之后還會執行localFinally

       這個action,有沒有感覺到已經把body切成了三塊?好了,下面看一個例子。

 

 1     static void Main(string[] args) 2         { 3             var list = new List<int>() { 10, 20, 30, 40 }; 4  5             var options = new ParallelOptions(); 6  7             var total = 0; 8  9             var result = Parallel.For(0, list.Count, () =>10             {11                 Console.WriteLine("------------  thead --------------");12 13                 return 1;14             },15               (i, loop, j) =>16               {17                   Console.WriteLine("------------  body --------------");18 19                   Console.WriteLine("i=" + list[i] + " j=" + j);20 21                   return list[i];22               },23               (i) =>24               {25                   Console.WriteLine("------------  tfoot --------------");26 27                   Interlocked.Add(ref total, i);28 29                   Console.WriteLine("total=" + total);30               });31 32             Console.WriteLine("iscompleted:" + result.IsCompleted);33             Console.Read();34         }
View Code

 

接下來我們再翻翻它的源代碼,由于源碼太多,里面神乎其神,我就找幾個好玩的地方。

<1>  我在里面找到了一個rangeManager分區函數,代碼復雜看不懂,貌似很強大。

 1         internal RangeManager(long nFromInclusive, long nToExclusive, long nStep, int nNumExpectedWorkers) 2         { 3             this.m_nCurrentIndexRangeToAssign = 0; 4             this.m_nStep = nStep; 5             if (nNumExpectedWorkers == 1) 6             { 7                 nNumExpectedWorkers = 2; 8             } 9             ulong num = (ulong)(nToExclusive - nFromInclusive);10             ulong num2 = num / (ulong)((long)nNumExpectedWorkers);11             num2 -= num2 % (ulong)nStep;12             if (num2 == 0uL)13             {14                 num2 = (ulong)nStep;15             }16             int num3 = (int)(num / num2);17             if (num % num2 != 0uL)18             {19                 num3++;20             }21             long num4 = (long)num2;22             this.m_indexRanges = new IndexRange[num3];23             long num5 = nFromInclusive;24             for (int i = 0; i < num3; i++)25             {26                 this.m_indexRanges[i].m_nFromInclusive = num5;27                 this.m_indexRanges[i].m_nSharedCurrentIndexOffset = null;28                 this.m_indexRanges[i].m_bRangeFinished = 0;29                 num5 += num4;30                 if (num5 < num5 - num4 || num5 > nToExclusive)31                 {32                     num5 = nToExclusive;33                 }34                 this.m_indexRanges[i].m_nToExclusive = num5;35             }36         }

 

<2> 我又找到了這個神奇的ParallelForReplicatingTask類。

 

那么下面問題來了,在單線程的for中,我可以continue,可以break,那么在Parallel.For中有嗎?因為是并行,所以continue基本上就沒有

存在價值,break的話確實有價值,這個就是委托中的ParallelLoopState做到的,并且還新增了一個Stop。

 

 

三:ForEach

其實ForEach和for在本質上是一樣的,你在源代碼中會發現在底層都是調用一個方法的,而ForEach會在底層中調用for共同的函數之前還會執行

其他的一些邏輯,所以這就告訴我們,能用Parallel.For的地方就不要用Parallel.ForEach,其他的都一樣了,這里就不贅述了。

 


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日韩有码在线电影| 欧美大片免费观看| 国产suv精品一区二区三区88区| 久久99久久99精品中文字幕| 成人网欧美在线视频| 久久偷看各类女兵18女厕嘘嘘| 欧洲中文字幕国产精品| 欧美日韩综合视频| 欧美国产日韩在线| 国产精品久久久久久超碰| 成人在线视频网站| 97涩涩爰在线观看亚洲| 国产精品扒开腿做爽爽爽的视频| 国产成人激情视频| 色吧影院999| 日韩在线视频线视频免费网站| 国产精品亚洲自拍| 欧美精品手机在线| 亚洲精品成a人在线观看| 日本午夜在线亚洲.国产| 黑人巨大精品欧美一区二区免费| 久久久久日韩精品久久久男男| 波霸ol色综合久久| 国产一区二区黑人欧美xxxx| 欧美视频一区二区三区…| 45www国产精品网站| 国产精品自产拍在线观看| 亚洲香蕉av在线一区二区三区| 欧美一区二区大胆人体摄影专业网站| 久久久成人精品| 中文字幕少妇一区二区三区| 国产成人精品久久久| 欧美日韩免费看| 欧美视频中文在线看| 日韩欧美国产高清91| 97av在线影院| 久久手机免费视频| 亚洲一区二区国产| 亚洲xxxx18| 久久久久久中文| 亚洲香蕉在线观看| 亚洲尤物视频网| 亚洲色图狂野欧美| 久久久久久亚洲| 亚洲黄色成人网| 日韩成人在线播放| 日本91av在线播放| 精品亚洲va在线va天堂资源站| 97久久精品在线| 亚洲天堂av图片| 91精品国产色综合久久不卡98口| 日本19禁啪啪免费观看www| 亚洲第一综合天堂另类专| 欧美激情啊啊啊| 欧美激情久久久久久| 国产在线精品成人一区二区三区| 国模极品一区二区三区| 欧美成人一二三| 欧美视频免费在线观看| 亚洲国产精品久久久| 欧美日韩精品在线播放| 日韩免费观看视频| 综合网中文字幕| 国产成人中文字幕| 国产精品极品在线| 亚洲欧美日韩国产中文| 国产亚洲日本欧美韩国| 97在线精品视频| 久久久精品美女| 亚洲欧美激情精品一区二区| 91免费看片网站| 精品少妇v888av| 97香蕉超级碰碰久久免费的优势| 日韩免费av在线| 欧美诱惑福利视频| 精品日韩中文字幕| 国产精品久久久久av免费| 国产精品老女人视频| 亚洲丝袜一区在线| 在线播放国产一区二区三区| 亚洲综合最新在线| 亚洲电影第1页| 成人a在线视频| 成人在线国产精品| 成人有码在线播放| 国外日韩电影在线观看| 欧美激情一区二区三区久久久| 性欧美xxxx视频在线观看| 欧美在线视频播放| 日韩精品免费综合视频在线播放| 亚洲xxxx18| 久久中文字幕在线视频| 国产精品久久9| 久久天天躁狠狠躁夜夜爽蜜月| 国产精品久久久久久久久免费看| 欧美诱惑福利视频| 欧美亚洲视频在线看网址| 日韩精品福利在线| 大桥未久av一区二区三区| 国模精品视频一区二区三区| 55夜色66夜色国产精品视频| 国产精品入口免费视| 国产一区二区丝袜| 国产做受69高潮| 亚洲女成人图区| 国产精品尤物福利片在线观看| 亚洲欧美国产高清va在线播| 欧美性视频精品| 日韩风俗一区 二区| 日韩成人在线电影网| 中文字幕亚洲在线| 日韩免费观看网站| 精品福利樱桃av导航| 午夜精品久久久久久久白皮肤| 国产精品日韩av| 欧美激情一区二区三区久久久| 成人精品aaaa网站| 中文字幕欧美日韩在线| 精品国产一区av| 中文字幕日韩综合av| 激情成人中文字幕| 欧美亚洲第一区| 国产精品精品视频一区二区三区| 国产精品九九久久久久久久| 欧美中文字幕第一页| 蜜臀久久99精品久久久无需会员| 国产精品高清在线| 精品久久久久久久久久ntr影视| 亚洲欧美日韩一区二区三区在线| 亚洲新中文字幕| 亚洲人成网站999久久久综合| 久久精品国产视频| 精品美女久久久久久免费| 亚洲一区二区中文字幕| 国产精品a久久久久久| 91精品国产91久久| 国产精品爽爽爽| 在线电影欧美日韩一区二区私密| 国产成人精品国内自产拍免费看| 精品视频在线导航| 中文字幕日韩高清| 美日韩精品免费观看视频| 欧美日韩一区二区免费在线观看| 欧美最猛性xxxxx亚洲精品| 国产精品嫩草影院久久久| 曰本色欧美视频在线| 亚洲a∨日韩av高清在线观看| 在线免费看av不卡| 久久99久国产精品黄毛片入口| 日韩电影大全免费观看2023年上| 欧美亚洲激情在线| 精品国产户外野外| 久久精品人人做人人爽| 国产精品福利在线观看网址| 热久久美女精品天天吊色| 精品自拍视频在线观看| 亚洲免费av网址| 国产欧美亚洲视频| 亚洲精品91美女久久久久久久| 日韩电视剧在线观看免费网站| 福利微拍一区二区| 国语自产精品视频在免费| 日韩欧美999| 中文字幕亚洲欧美日韩高清|