C#多線程之Parallel類(lèi)的用法
Parallel類(lèi)是對(duì)線程的一個(gè)抽象。該類(lèi)位于System.Threading.Tasks名稱(chēng)空間中,提供了數(shù)據(jù)和任務(wù)并行性。
Paraller類(lèi)定義了數(shù)據(jù)并行地For和ForEach的靜態(tài)方法,以及任務(wù)并行的Invoke的靜態(tài)方法。Parallel.For()和Parallel.ForEach()方法在每次迭代中調(diào)用相同的代碼,Paraller.Invoke()允許調(diào)用不同的方法。
1.Parallel.For
Parallel.For()方法類(lèi)似C#語(yǔ)法的for循環(huán)語(yǔ)句,多次執(zhí)行一個(gè)任務(wù)。但該方法并行運(yùn)行迭代,迭代的順序沒(méi)有定義。
Parallel.For()方法中,前兩個(gè)參數(shù)定義了循環(huán)的開(kāi)頭和結(jié)束,第三個(gè)參數(shù)是一個(gè)Action委托。Parallel.For方法返回類(lèi)型是ParallelLoopResult結(jié)構(gòu),它提供了循環(huán)是否結(jié)束的信息。
Parallel.For有多個(gè)重載版本和多個(gè)泛型重載版本。
示例:
static void ForTest() { ParallelLoopResult plr = Parallel.For(0,10,i => { Console.WriteLine("{0},task:{1},thread:{2}",i,Task.CurrentId,Thread.CurrentThread.ManagedThreadId); Thread.Sleep(5000); }); if (plr.IsCompleted) Console.WriteLine("completed!"); }
輸出:
任務(wù)不一定映射到一個(gè)線程上。線程也可以被不同的任務(wù)重用。
上面的例子,使用了.NET 4.5中新增的Thread.Sleep方法,而不是Task.Delay方法。Task.Delay是一個(gè)異步(http://www.cnblogs.com/afei-24/p/6757361.html)方法,用于釋放線程供其它任務(wù)使用。
示例:
static void ForTestDelay() { ParallelLoopResult plr = Parallel.For(0, 10,async i => { Console.WriteLine("{0},task:{1},thread:{2}", i, Task.CurrentId, Thread.CurrentThread.ManagedThreadId); await Task.Delay(1000); Console.WriteLine("{0},task:{1},thread:{2}", i, Task.CurrentId, Thread.CurrentThread.ManagedThreadId); }); if (plr.IsCompleted) Console.WriteLine("completed!"); Console.ReadKey(); }
輸出:
上面代碼使用了await關(guān)鍵字進(jìn)行延遲,輸出結(jié)果顯示延遲前后的代碼運(yùn)行在不同的線程中。而且延遲后的任務(wù)不再存在,只留下線程,這里還重用了前面的線程。另一個(gè)重要的方面是,Parallel類(lèi)的For方法并沒(méi)有等待延遲,而是直接完成。parallel類(lèi)只等待它創(chuàng)建的任務(wù),而不等待其它后臺(tái)活動(dòng)。所以上面代碼使用了Console.ReadKey();使主線程一直運(yùn)行,不然很可能看不到后面的輸出。
2.提前停止Parallel.For
For()方法的一個(gè)重載版本接受第三個(gè)Action<int,ParallelLoopState>委托類(lèi)型的參數(shù)。使用這個(gè)方法可以調(diào)用ParallelLoopState的Break()或Stop()方法,以停止循環(huán)。
注意,前面說(shuō)到,迭代的順序是沒(méi)有定義的。
示例:
static void ForStop() { ParallelLoopResult plr = Parallel.For(0,10,(int i,ParallelLoopState pls)=> { Console.WriteLine("{0},task:{1},thread:{2}", i, Task.CurrentId, Thread.CurrentThread.ManagedThreadId); if (i > 5) pls.Break(); }); Console.WriteLine("is completed:{0}",plr.IsCompleted); Console.WriteLine("最低停止索引:{0}",plr.LowestBreakIteration); }
輸出:
迭代值在大于5時(shí)中斷,但其它已開(kāi)始的任務(wù)同時(shí)執(zhí)行。
3.對(duì)Parallel.For中的每個(gè)線程初始化
Parallel.For方法使用多個(gè)線程來(lái)執(zhí)行循環(huán),如果需要對(duì)每個(gè)線程進(jìn)行初始化,就可以使用Parallel.For<TLocal>()方法。除了from和to對(duì)應(yīng)的值之外,Parallel.For方法的泛型版本還接受3個(gè)委托參數(shù):
第一個(gè)委托參數(shù)的類(lèi)型是Func<TLocal>,這個(gè)方法僅對(duì)用于執(zhí)行迭代的每個(gè)線程調(diào)用每一次。
第二個(gè)委托參數(shù)為循環(huán)體定義了委托。該參數(shù)類(lèi)型是Func<int, ParallelLoopState, TLocal, TLocal>。其中第一個(gè)參數(shù)是循環(huán)迭代,第二個(gè)參數(shù)ParallelLoopState允許停止循環(huán),第三個(gè)參數(shù)接受從上面參數(shù)委托Func<TLocal>返回的值,該委托還需返回一個(gè)TLocal類(lèi)型的值。該方法對(duì)每次迭代調(diào)用。
第三個(gè)委托參數(shù)指定一個(gè)委托Action<TLocal>,接受第二個(gè)委托參數(shù)的返回值。這個(gè)方法僅對(duì)用于執(zhí)行迭代的每個(gè)線程調(diào)用每一次。
示例:
static void ForInit() { ParallelLoopResult plr = Parallel.For(0,10,()=> { Console.WriteLine("init thread:{0},task:{1}",Thread.CurrentThread.ManagedThreadId,Task.CurrentId); return Thread.CurrentThread.ManagedThreadId.ToString(); }, (i, pls,strInit)=> { Console.WriteLine("body:{0},strInit:{1},thraed:{2},task:{3}",i,strInit,Thread.CurrentThread.ManagedThreadId,Task.CurrentId); return i.ToString(); }, (strI)=> { Console.WriteLine("finally {0}",strI); }); }
輸出:
4.Parallel.ForEach
Parallel.ForEach方法遍歷實(shí)現(xiàn)了IEnumerable的集合,類(lèi)似于foreach,但以異步方式遍歷。沒(méi)有確定遍歷順序。
示例:
static void ForeachTest() { string[] data = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve" }; ParallelLoopResult plr = Parallel.ForEach<string>(data, s => { Console.WriteLine(s); }); if (plr.IsCompleted) Console.WriteLine("completed!"); }
如果需要中斷,可以使用ForEach的重載版本和參數(shù)ParallelLoopState。
訪問(wèn)索引器:
ParallelLoopResult plr1 = Parallel.ForEach<string>(data, (s,pls,l) => { Console.WriteLine("data:{0},index:{1}",s,l); });
5.Parallel.Invoke
如果多個(gè)任務(wù)并行運(yùn)行,可以使用Parallel.Invoke方法。該方法允許傳遞一個(gè)Action委托數(shù)組。
static void ParallerInvoke() { Action[] funs = { Fun1,Fun2}; Parallel.Invoke(funs); } static void Fun1() { Console.WriteLine("f1"); Console.WriteLine("task:{0},thread:{1}", Task.CurrentId, Thread.CurrentThread.ManagedThreadId); } static void Fun2() { Console.WriteLine("f2"); Console.WriteLine("task:{0},thread:{1}", Task.CurrentId, Thread.CurrentThread.ManagedThreadId); }
到此這篇關(guān)于C#多線程之Parallel類(lèi)的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
C#添加Windows服務(wù) 定時(shí)任務(wù)
這篇文章主要為大家詳細(xì)介紹了C#添加Windows服務(wù),定時(shí)任務(wù)的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-01-01Linq兩個(gè)List集合取交集的實(shí)現(xiàn)
這篇文章主要介紹了Linq兩個(gè)List集合取交集的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12C#結(jié)合JavaScript實(shí)現(xiàn)秒殺倒計(jì)時(shí)的方法
這篇文章主要介紹了C#結(jié)合JavaScript實(shí)現(xiàn)秒殺倒計(jì)時(shí)的方法,涉及C#結(jié)合javascript操作時(shí)間的技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-04-04詳解C#實(shí)例化對(duì)象的三種方式及性能對(duì)比
這篇文章主要介紹了C#實(shí)例化對(duì)象的三種方式及性能對(duì)比,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12