版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、詳細(xì)的.Net并行編程高級教程-Parallel一直覺得自己對并發(fā)了解不夠深入,特別是看了代碼整潔之道覺得自己有必要好好學(xué)學(xué)并發(fā)編程,因?yàn)樾阅芤彩呛饬看a整潔的一大標(biāo)準(zhǔn)。而且在失控這本書中也多次提到并發(fā),不管是計(jì)算機(jī)還是生物都并發(fā)處理著各種事物。人真是奇怪,當(dāng)你關(guān)注一個(gè)事情的時(shí)候,你會發(fā)現(xiàn)周圍的事物中就常出現(xiàn)那個(gè)事情。所以好奇心驅(qū)使下學(xué)習(xí)并發(fā)。便有了此文。一、理解硬件線程和軟件線程 多核處理器帶有一個(gè)以上的物理內(nèi)核-物理內(nèi)核是真正的獨(dú)立處理單元,多個(gè)物理內(nèi)核使得多條指令能夠同時(shí)并行運(yùn)行。硬件線程也稱為邏輯內(nèi)核,一個(gè)物理內(nèi) 核可以使用超線程技術(shù)提供多個(gè)硬件線程。所以一個(gè)硬件線程并不代表一個(gè)物理內(nèi)
2、核;Windows中每個(gè)運(yùn)行的程序都是一個(gè)進(jìn)程,每一個(gè)進(jìn)程都會創(chuàng)建并運(yùn)行 一個(gè)或多個(gè)線程,這些線程稱為軟件線程。硬件線程就像是一條泳道,而軟件線程就是在其中游泳的人。二、并行場合 .Net Framework4 引入了新的Task Parallel Library(任務(wù)并行庫,TPL),它支持?jǐn)?shù)據(jù)并行、任務(wù)并行和流水線。讓開發(fā)人員應(yīng)付不同的并行場合。 數(shù)據(jù)并行:有大量數(shù)據(jù)需要處理,并且必須對每一份數(shù)據(jù)執(zhí)行同樣的操作。比如通過256bit的密鑰對100個(gè)Unicode字符串進(jìn)行AES算法加密。 任務(wù)并行:通過任務(wù)并發(fā)運(yùn)行不同的操作。例如生成文件散列碼,加密字符串,創(chuàng)建縮略圖。 流水線:這是任務(wù)并
3、行和數(shù)據(jù)并行的結(jié)合體。 TPL引入了System.Threading.Tasks ,主類是Task,這個(gè)類表示一個(gè)異步的并發(fā)的操作,然而我們不一定要使用Task類的實(shí)例,可以使用Parallel靜態(tài)類。它提供了 Parallel.Invoke, Parallel.For Parallel.Forecah 三個(gè)方法。三、Parallel.Invoke 試圖讓很多方法并行運(yùn)行的最簡單的方法就是使用Parallel類的Invoke方法。例如有四個(gè)方法: WatchMovie HaveDinner ReadBook WriteBlog 通過下面的代碼就可以使用并行。System.Threading.T
4、asks.Parallel.Invoke(WatchMovie, HaveDinner, ReadBook, WriteBlog);這段代碼會創(chuàng)建指向每一個(gè)方法的委托。Invoke方法接受一個(gè)Action的參數(shù)組。1public static void Invoke(params Action actions);用lambda表達(dá)式或匿名委托可以達(dá)到同樣的效果。System.Threading.Tasks.Parallel.Invoke() = WatchMovie(), () = HaveDinner(), () = ReadBook(), delegate() WriteBlog(); )
5、;1.沒有特定的執(zhí)行順序。Parallel.Invoke方法只有在4個(gè)方法全部完成之后才會返回。它至少需要4個(gè)硬件線程才足以讓這4個(gè)方法并發(fā)運(yùn)行。但并不保證這4個(gè)方法能夠同時(shí)啟動(dòng)運(yùn)行,如果一個(gè)或者多個(gè)內(nèi)核處于繁忙狀態(tài),那么底層的調(diào)度邏輯可能會延遲某些方法的初始化執(zhí)行。給方法加上延時(shí),就可以看到必須等待最長的方法執(zhí)行完成才回到主方法。1. staticvoidMain(stringargs)2. 3. System.Threading.Tasks.Parallel.Invoke(WatchMovie,HaveDinner,ReadBook,4. WriteBlog);5. Console.Wri
6、teLine(執(zhí)行完成);6. Console.ReadKey();7. 8. 9. staticvoidWatchMovie()10. 11. Thread.Sleep(5000);12. Console.WriteLine(看電影);13. 14. staticvoidHaveDinner()15. 16. Thread.Sleep(1000);17. Console.WriteLine(吃晚飯);18. 19. staticvoidReadBook()20. 21. Thread.Sleep(2000);22. Console.WriteLine(讀書);23. 24. staticvo
7、idWriteBlog()25. 26. Thread.Sleep(3000);27. Console.WriteLine(寫博客);28. 這樣會造成很多邏輯內(nèi)核處于長時(shí)間閑置狀態(tài)。四、Parallel.ForParallel.For為固定數(shù)目的獨(dú)立For循環(huán)迭代提供了負(fù)載均衡 (即將工作分發(fā)到不同的任務(wù)中執(zhí)行,這樣所有的任務(wù)在大部分時(shí)間都可以保持繁忙) 的并行執(zhí)行。從而能盡可能地充分利用所有的可用的內(nèi)核。我們比較下下面兩個(gè)方法,一個(gè)使用For循環(huán),一個(gè)使用Parallel.For 都是生成密鑰在轉(zhuǎn)換為十六進(jìn)制字符串。1. privatestaticvoidGenerateAESKeys()
8、2. 3. varsw=Stopwatch.StartNew();4. for(inti=0;i18. 19. varaesM=newAesManaged();20. aesM.GenerateKey();21. byteresult=aesM.Key;22. stringhexStr=ConverToHexString(result);23. );24. 25. Console.WriteLine(Parallel_AES:+sw.Elapsed.ToString();26. private static int NUM_AES_KEYS = 100000; static void Main
9、(string args) Console.WriteLine(執(zhí)行+NUM_AES_KEYS+次:); GenerateAESKeys(); ParallelGenerateAESKeys(); Console.ReadKey(); 執(zhí)行1000000次這里并行的時(shí)間是串行的一半。五、Parallel.ForEach在Parallel.For中,有時(shí)候?qū)扔醒h(huán)進(jìn)行優(yōu)化可能會是一個(gè)非常復(fù)雜的任務(wù)。Parallel.ForEach為固定數(shù)目的獨(dú)立For Each循環(huán)迭代提供了負(fù)載均衡的并行執(zhí)行,且支持自定義分區(qū)器,讓使用者可以完全掌握數(shù)據(jù)分發(fā)。實(shí)質(zhì)就是將所有要處理的數(shù)據(jù)區(qū)分為多個(gè)部分,然后并行
10、運(yùn) 行這些串行循環(huán)。修改上面的代碼:1. System.Threading.Tasks.Parallel.ForEach(Partitioner.Create(1,NUM_AES_KEYS+1),range=2. 3. varaesM=newAesManaged();4. Console.WriteLine(AESRange(0,1循環(huán)開始時(shí)間:2),range.Item1,range.Item2,DateTime.Now.TimeOfDay);5. 6. for(inti=range.Item1;irange.Item2;i+)7. 8. aesM.GenerateKey();9. byte
11、result=aesM.Key;10. stringhexStr=ConverToHexString(result);11. 12. Console.WriteLine(AES:+sw.Elapsed.ToString();13. );從執(zhí)行結(jié)果可以看出,分了13個(gè)段執(zhí)行的。第二次執(zhí)行還是13個(gè)段。速度上稍微有差異。開始沒有指定分區(qū)數(shù),Partitioner.Create使用的是內(nèi)置默認(rèn)值。而且我們發(fā)現(xiàn)這些分區(qū)并不是同時(shí)執(zhí)行的,大致是分了三個(gè)時(shí)間段執(zhí)行。而且執(zhí)行順序是不同的??偟臅r(shí)間和Parallel.For的方法差不多。public static ParallelLoopResult For
12、Each(Partitioner source, Action body)Parallel.ForEach方法定義了source和Body兩個(gè)參數(shù)。source是指分區(qū)器。提供了分解為多個(gè)分區(qū)的數(shù)據(jù)源。body是 要調(diào)用的委托。它接受每一個(gè)已定義的分區(qū)作為參數(shù)。一共有20多個(gè)重載,在上面的例子中,分區(qū)的類型為Tuple,是一個(gè) 二元組類型。此外,返回一個(gè)ParallelLoopResult的值。Partitioner.Create 創(chuàng)建分區(qū)是根據(jù)邏輯內(nèi)核數(shù)及其他因素決定。1. publicstaticOrderablePartitionerTupleCreate(intfromInclusiv
13、e,inttoExclusive)2. 3. intnum=3;4. if(toExclusive=fromInclusive)5. thrownewArgumentOutOfRangeException(toExclusive);6. intrangeSize=(toExclusive-fromInclusive)/(PlatformHelper.ProcessorCount*num);7. if(rangeSize=0)8. rangeSize=1;9. returnPartitioner.CreateTuple(Partitioner.CreateRanges(fromInclusive
14、,toExclusive,rangeSize),EnumerablePartitionerOptions.NoBuffering);10. 因此我們可以修改分區(qū)數(shù)目,rangesize大致為250000左右。也就是說我的邏輯內(nèi)核是4.var rangesize = (int) (NUM_AES_KEYS/Environment.ProcessorCount) + 1; System.Threading.Tasks.Parallel.ForEach(Partitioner.Create(1, NUM_AES_KEYS + 1,rangesize), range =再次執(zhí)行:分區(qū)變成了四個(gè),時(shí)間上
15、沒有多大差別(第一個(gè)時(shí)間是串行時(shí)間)。我們看見這四個(gè)分區(qū)幾乎是同時(shí)執(zhí)行的。大部分情況下,TPL在幕后使用的負(fù)載均衡機(jī)制都是非常高效的,然而對分區(qū)的控制便于使用者對自己的工作負(fù)載進(jìn)行分析,來改進(jìn)整體的性能。Parallel.ForEach也能對IEnumerable集合進(jìn)行重構(gòu)。Enumerable.Range生產(chǎn)了序列化的數(shù)目。但這樣就沒有上面的分區(qū)效果。1. privatestaticvoidParallelForEachGenerateMD5HasHes()2. 3. varsw=Stopwatch.StartNew();4. System.Threading.Tasks.Parallel
16、.ForEach(Enumerable.Range(1,NUM_AES_KEYS),number=5. 6. varmd5M=MD5.Create();7. bytedata=Encoding.Unicode.GetBytes(Environment.UserName+number);8. byteresult=md5M.ComputeHash(data);9. stringhexString=ConverToHexString(result);10. );11. Console.WriteLine(MD5:+sw.Elapsed.ToString();12. 六、從循環(huán)中退出和串行運(yùn)行中的b
17、reak不同,ParallelLoopState 提供了兩個(gè)方法用于停止Parallel.For 和 Parallel.ForEach的執(zhí)行。 Break:讓循環(huán)在執(zhí)行了當(dāng)前迭代后盡快停止執(zhí)行。比如執(zhí)行到100了,那么循環(huán)會處理掉所有小于100的迭代。 Stop:讓循環(huán)盡快停止執(zhí)行。如果執(zhí)行到了100的迭代,那不能保證處理完所有小于100的迭代。修改上面的方法:執(zhí)行3秒后退出。1. privatestaticvoidParallelLoopResult(ParallelLoopResultloopResult)2. 3. stringtext;4. if(loopResult.IsComple
18、ted)5. 6. text=循環(huán)完成;7. 8. else9. 10. if(loopResult.LowestBreakIteration.HasValue)11. 12. text=Break終止;13. 14. else15. 16. text=Stop終止;17. 18. 19. Console.WriteLine(text);20. 21. 22. 23. privatestaticvoidParallelForEachGenerateMD5HasHesBreak()24. 25. varsw=Stopwatch.StartNew();26. varloopresult=Syste
19、m.Threading.Tasks.Parallel.ForEach(Enumerable.Range(1,NUM_AES_KEYS),(intnumber,ParallelLoopStateloopState)=27. 28. varmd5M=MD5.Create();29. bytedata=Encoding.Unicode.GetBytes(Environment.UserName+number);30. byteresult=md5M.ComputeHash(data);31. stringhexString=ConverToHexString(result);32. if(sw.El
20、apsed.Seconds3)33. 34. loopState.Stop();35. 36. );37. ParallelLoopResult(loopresult);38. Console.WriteLine(MD5:+sw.Elapsed);39. 七、捕捉并行循環(huán)中發(fā)生的異常。當(dāng)并行迭代中調(diào)用的委托拋出異常,這個(gè)異常沒有在委托中被捕獲到時(shí),就會變成一組異常,新的System.AggregateException負(fù)責(zé)處理這一組異常。1. privatestaticvoidParallelForEachGenerateMD5HasHesException()2. 3. varsw=Stop
21、watch.StartNew();4. varloopresult=newParallelLoopResult();5. try6. 7. loopresult=System.Threading.Tasks.Parallel.ForEach(Enumerable.Range(1,NUM_AES_KEYS),(number,loopState)=8. 9. varmd5M=MD5.Create();10. bytedata=Encoding.Unicode.GetBytes(Environment.UserName+number);11. byteresult=md5M.ComputeHash(
22、data);12. stringhexString=ConverToHexString(result);13. if(sw.Elapsed.Seconds3)14. 15. thrownewTimeoutException(執(zhí)行超過三秒);16. 17. );18. 19. catch(AggregateExceptionex)20. 21. foreach(varinnerExinex.InnerExceptions)22. 23. Console.WriteLine(innerEx.ToString();24. 25. 26. 27. ParallelLoopResult(loopresult);28. Console.WriteLine(MD5:+sw.Elapsed);29. 結(jié)果:異常出現(xiàn)了好幾次。八、指定并行度。TPL的方法總會試圖利用所有可用的邏輯內(nèi)核來實(shí)現(xiàn)最好的結(jié)果,但有時(shí)候你并不希望在并行循環(huán)中使用所有的內(nèi)核。比如你需要留出一個(gè)不參與并行計(jì)算 的內(nèi)核,來創(chuàng)建能夠響應(yīng)用戶的應(yīng)用程序,而且這個(gè)內(nèi)核需要幫助你運(yùn)行代碼中的其他部分。這個(gè)時(shí)候一種好的解決方法就是指定最大并行度。這需要?jiǎng)?chuàng)建一個(gè)ParallelOptions的實(shí)例,設(shè)置M
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2024年建筑安裝工程承包合同
- 2024年度新能源發(fā)電EPC施工合同
- 股票課件教學(xué)課件
- 2024年城市規(guī)劃地形測繪專項(xiàng)協(xié)議
- 2024年度旅游景區(qū)開發(fā)合同
- 2024年企業(yè)信息安全服務(wù)合同
- 2024年度CRM系統(tǒng)服務(wù)合同:提供銷售合同管理專業(yè)支持
- 2024年亞太地區(qū)進(jìn)出口合作協(xié)議
- 2024基于物聯(lián)網(wǎng)技術(shù)的服務(wù)合同研究
- 2024年度煤炭供應(yīng)合同
- 摩托車維修技術(shù)考核試卷
- 6 我的家庭貢獻(xiàn)與責(zé)任(教學(xué)設(shè)計(jì)) 部編版道德與法治四年級上冊
- 2024七年級英語下冊 Unit 6 I'm watching TV教案設(shè)計(jì)(新版)人教新目標(biāo)版
- 期中測試題-2024-2025學(xué)年道德與法治六年級上冊統(tǒng)編版
- 《珍愛生命拒絕毒品》主題班會課件
- 2024年貴州畢節(jié)市委政法委所屬事業(yè)單位考調(diào)6人歷年高頻500題難、易錯(cuò)點(diǎn)模擬試題附帶答案詳解
- GB/T 32399-2024信息技術(shù)云計(jì)算參考架構(gòu)
- 2024粵東西粵北地區(qū)教師全員輪訓(xùn)培訓(xùn)心得總結(jié)
- 安全生產(chǎn)治本攻堅(jiān)三年行動(dòng)方案2024~2026(工貿(mào))
- 人教版九年級數(shù)學(xué)下冊相似《相似三角形(第4課時(shí))》示范教學(xué)課件
- 2024年新高考試題分析及2025屆備考策略建議課件
評論
0/150
提交評論