C#并行编程中的Parallel.Invoke
一、基礎(chǔ)知識
???? 并行編程:并行編程是指軟件開發(fā)的代碼,它能在同一時(shí)間執(zhí)行多個(gè)計(jì)算任務(wù),提高執(zhí)行效率和性能一種編程方式,屬于多線程編程范疇。所以我們在設(shè)計(jì)過程中一般會(huì)將很多任務(wù)劃分成若干個(gè)互相獨(dú)立子任務(wù),這些任務(wù)不考慮互相的依賴和順序。這樣我們就可以使用很好的使用并行編程。但是我們都知道多核處理器的并行設(shè)計(jì)使用共享內(nèi)存,如果沒有考慮并發(fā)問題,就會(huì)有很多異常和達(dá)不到我們預(yù)期的效果。不過還好NET Framework4.0引入了Task Parallel Library(TPL)實(shí)現(xiàn)了基于任務(wù)設(shè)計(jì)而不用處理重復(fù)復(fù)雜的線程的并行開發(fā)框架。它支持?jǐn)?shù)據(jù)并行,任務(wù)并行與流水線。核心主要是Task,但是一般簡單的并行我們可以利用Parallel提供的靜態(tài)類如下三個(gè)方法。
???????? Parallel.Invoke? 對給定任務(wù)實(shí)現(xiàn)并行開發(fā)
???????? Parallel.For? 對固定數(shù)目的任務(wù)提供循環(huán)迭代并行開發(fā)
???????? parallel.Foreach?對固定數(shù)目的任務(wù)提供循環(huán)迭代并行開發(fā)
注意:所有的并行開發(fā)不是簡單的以為只要將For或者Foreach換成Parallel.For與Parallel.Foreach這樣簡單。
PS:從簡單的Invoke開始逐步深入探討并行開發(fā)的主要知識點(diǎn),也對自己學(xué)習(xí)過程中的積累做個(gè)總結(jié),其中參考了博客園中的其他優(yōu)秀博文
??????滴答的雨?異步編程:輕量級線程同步基元對象
????? 首先感謝您,在我學(xué)習(xí)并行開發(fā)過程中,您的博文對我?guī)椭艽蟆?/p>
二、Parallel.Invoke在并行中的使用
????? 首先我們來看看它的兩個(gè)重載方法:????
public static void Invoke(params Action[] actions); public static void Invoke(ParallelOptions parallelOptions, params Action[] actions);???????Invoke主要接受params的委托actions,比如我們要同時(shí)執(zhí)行三個(gè)任務(wù),我們可以這樣利用 ????
方式一Parallel.Invoke(() => Task1(), () => Task2(), () => Task3());
方式二
Parallel.Invoke(Task1, Task2, Task3);
方式三
Parallel.Invoke(
??????????????? () =>
??????????????? {
??????????????????? Task1();
??????????????? },
?????????????? Task2,
???????????? ?? delegate () { Task3(); console.write('do someting!');});
這樣Invoke就簡單實(shí)現(xiàn)了Task1,Task2,Task3的并行開發(fā)。下面我們用實(shí)例來說明他們的執(zhí)行規(guī)則。以及兩個(gè)重載方法的使用。
三 、Demo
???? 1、 Demo 1:
public class ParallelInvoke{/// <summary>/// Invoke方式一 action/// </summary>public void Client1(){Stopwatch stopWatch = new Stopwatch();Console.WriteLine("主線程:{0}線程ID : {1};開始", "Client1", Thread.CurrentThread.ManagedThreadId);stopWatch.Start();Parallel.Invoke(() => Task1("task1"), () => Task2("task2"), () => Task3("task3"));stopWatch.Stop();Console.WriteLine("主線程:{0}線程ID : {1};結(jié)束,共用時(shí){2}ms", "Client1", Thread.CurrentThread.ManagedThreadId, stopWatch.ElapsedMilliseconds);}private void Task1(string data){Thread.Sleep(5000);Console.WriteLine("任務(wù)名:{0}線程ID : {1}", data, Thread.CurrentThread.ManagedThreadId);}private void Task2(string data){Console.WriteLine("任務(wù)名:{0}線程ID : {1}", data, Thread.CurrentThread.ManagedThreadId);}private void Task3(string data){Console.WriteLine("任務(wù)名:{0}線程ID : {1}", data, Thread.CurrentThread.ManagedThreadId);} }執(zhí)行運(yùn)行后結(jié)果:
我們看到Invoke 執(zhí)行Task三個(gè)方法主要有以下幾個(gè)特點(diǎn):
????? 1、沒有固定的順序,每個(gè)Task可能是不同的線程去執(zhí)行,也可能是相同的;
????? 2、主線程必須等Invoke中的所有方法執(zhí)行完成后返回才繼續(xù)向下執(zhí)行;這樣對我們以后設(shè)計(jì)并行的時(shí)候,要考慮每個(gè)Task任務(wù)盡可能差不多,如果相差很大,比如一個(gè)時(shí)間非常長,其他都比較短,這樣一個(gè)線程可能會(huì)影響整個(gè)任務(wù)的性能。這點(diǎn)非常重要
????? 3、這個(gè)非常簡單就實(shí)現(xiàn)了并行,不用我們考慮線程問題。主要Framework已經(jīng)為我們控制好線程池的問題。
ps:如果其中有一個(gè)異常怎么辦? 帶做這個(gè)問題修改了增加了一個(gè)Task4.
??? 2、 Demo2??
public class ParallelInvoke{/// <summary>/// Invoke方式一 action/// </summary>public void Client1(){Stopwatch stopWatch = new Stopwatch();Console.WriteLine("主線程:{0}線程ID : {1};開始", "Client1", Thread.CurrentThread.ManagedThreadId);stopWatch.Start();try{Parallel.Invoke(() => Task1("task1"), () => Task2("task2"), () => Task3("task3"), delegate () { throw new Exception("我這里發(fā)送了異常"); });}catch (AggregateException ae){foreach (var ex in ae.InnerExceptions)Console.WriteLine(ex.Message);}stopWatch.Stop();Console.WriteLine("主線程:{0}線程ID : {1};結(jié)束,共用時(shí){2}ms", "Client1", Thread.CurrentThread.ManagedThreadId, stopWatch.ElapsedMilliseconds);}}主要看?delegate() {?throw?new Exception("我這里發(fā)送了異常");} 增加了這個(gè)委托Task3. 然后我們看結(jié)果:
??? 這里我們發(fā)現(xiàn)即使有異常程序也會(huì)完成執(zhí)行,而且不會(huì)影響其他Task的執(zhí)行。
??? 3、demo3 重載方法ParallelOptions 的使用。
?? 理解ParallelOptions建議大家異步編程:輕量級線程同步基元對象???講的非常詳細(xì)。
?? 主要理解兩個(gè)參數(shù):
?? ? CancellationToken???? 控制線程的取消
???? MaxDegreeOfParallelism? 設(shè)置最大的線程數(shù),有時(shí)候可能會(huì)跑遍所有的內(nèi)核,為了提高其他應(yīng)用程序的穩(wěn)定性,就要限制參與的內(nèi)核
???? 下面從代碼上看效果如何?
public class ParallelInvoke{// 定義CancellationTokenSource 控制取消readonly CancellationTokenSource _cts = new CancellationTokenSource();/// <summary>/// Invoke方式一 action/// </summary>public void Client1(){Console.WriteLine("主線程:{0}線程ID : {1};開始{2}", "Client3", Thread.CurrentThread.ManagedThreadId, DateTime.Now);var po = new ParallelOptions{CancellationToken = _cts.Token, // 控制線程取消MaxDegreeOfParallelism = 3 // 設(shè)置最大的線程數(shù)3,仔細(xì)觀察線程ID變化};Parallel.Invoke(po, () => Task1("task1"), ()=>Task5(po), Task6);Console.WriteLine("主線程:{0}線程ID : {1};結(jié)束{2}", "Client3", Thread.CurrentThread.ManagedThreadId, DateTime.Now);}private void Task1(string data){Thread.Sleep(5000);Console.WriteLine("任務(wù)名:{0}線程ID : {1}", data, Thread.CurrentThread.ManagedThreadId);}// 打印數(shù)字private void Task5(ParallelOptions po){Console.WriteLine("進(jìn)入Task5線程ID : {0}", Thread.CurrentThread.ManagedThreadId);int i = 0;while (i < 100){// 判斷是否已經(jīng)取消if (po.CancellationToken.IsCancellationRequested){Console.WriteLine("已經(jīng)被取消。");return;}Thread.Sleep(100);Console.Write(i + " ");Interlocked.Increment(ref i);}}/// <summary>/// 10秒后取消/// </summary>private void Task6(){Console.WriteLine("進(jìn)入取消任務(wù),Task6線程ID : {0}", Thread.CurrentThread.ManagedThreadId);Thread.Sleep(1000 * 10);_cts.Cancel();Console.WriteLine("發(fā)起取消請求...........");} }
執(zhí)行結(jié)果:
???? 從程序結(jié)果我們看到以下特點(diǎn):
??????????? 1、程序在執(zhí)行過程中線程數(shù)碼不超過3個(gè)。
??????????? 2、CancellationTokenSource/CancellationToken控制任務(wù)的取消。
四、總結(jié)
? ? ? Parallel.Invoke 的使用過程中我們要注意以下特點(diǎn):
????? 1、沒有特定的順序,Invoke中的方法全部執(zhí)行完才返回,但是即使有異常在執(zhí)行過程中也同樣會(huì)完成,他只是一個(gè)很簡單的并行處理方法,特點(diǎn)就是簡單,不需要我們考慮線程的問題。
????? 2、如果在設(shè)計(jì)Invoke中有個(gè)需要很長時(shí)間,這樣會(huì)影響整個(gè)Invoke的效率和性能,這個(gè)我們在設(shè)計(jì)每個(gè)task時(shí)候必須去考慮的。
????? 3、Invoke 參數(shù)是委托方法。
????? 4、當(dāng)然Invoke在每次調(diào)用都有開銷的,不一定并行一定比串行好,要根據(jù)實(shí)際情況,內(nèi)核環(huán)境多次測試調(diào)優(yōu)才可以。
????? 5、異常處理比較復(fù)雜。
總結(jié)
以上是生活随笔為你收集整理的C#并行编程中的Parallel.Invoke的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: .NET 4.0 任务(Task)
- 下一篇: 南昌公安厅离融创中心多远距离