DotNet并行計(jì)算的使用誤區(qū)二
并行計(jì)算或稱平行計(jì)算是相對(duì)于串行計(jì)算來(lái)說(shuō)的。所謂并行計(jì)算可分為時(shí)間上的并行和空間上的并行。 時(shí)間上的并行就是指流水線技術(shù),而空間上的并行則是指用多個(gè)處理器并發(fā)的執(zhí)行計(jì)算。
誤區(qū)三 . 并行計(jì)算是運(yùn)行時(shí)的事
的確,DotNet會(huì)在運(yùn)行時(shí)決定是否使用并行庫(kù)處理代碼,但是早在你編譯代碼時(shí),編譯器就早已為這一時(shí)刻做好準(zhǔn)備,換就話說(shuō):
1. 使用并行庫(kù)處理代碼與普通方式對(duì)比,IL的結(jié)構(gòu)是不同的。
2. 即使你選擇使用并行計(jì)算,并且你也確實(shí)擁有多核(線程)CPU,運(yùn)行時(shí)你的代碼也不一定是并行的。
使用TPL后CLR可能會(huì)分解任務(wù),這一依據(jù)的其中之一是由IL支持的,IL將并行的任務(wù)代碼分離,以便在將來(lái)的操作中并行,這一點(diǎn)可以從以下的示例中看出來(lái),以下兩段示例的核心C#代碼都是Tostring()和Sleep(),Code A使用For包含Sleep,Code B使用Parallel.For處理:
Code Part A:
IL:
- IL_000e: callvirt instance void [System]System.Diagnostics.Stopwatch::Start()
- IL_0013: nop
- IL_0014: ldc.i4.0
- IL_0015: stloc.2
- IL_0016: br.s IL_0031
- IL_0018: nop
- IL_0019: ldloca.s i
- IL_001b: call instance string [mscorlib]System.Int32::ToString()
- IL_0020: stloc.0
- IL_0021: ldc.i4 0xc8
- IL_0026: call void [mscorlib]System.Threading.Thread::Sleep(int32)
- IL_002b: nop
- IL_002c: nop
- IL_002d: ldloc.2
- IL_002e: ldc.i4.1
- IL_002f: add
- IL_0030: stloc.2
- IL_0031: ldloc.2
- IL_0032: ldc.i4.s 10
- IL_0034: clt
- IL_0036: stloc.3
- IL_0037: ldloc.3
- IL_0038: brtrue.s IL_0018
- IL_003a: ldloc.1
- IL_003b: callvirt instance void [System]System.Diagnostics.Stopwatch::Stop()
我們注意到,Code Part A的Sleep是直接出現(xiàn)在Load方法中的。
再來(lái)看看Parallel方式:
Code Part B:
Form1_Load:
- IL_0019: callvirt instance void [System]System.Diagnostics.Stopwatch::Start()
- IL_001e: nop
- IL_001f: ldc.i4.0
- IL_0020: ldc.i4.s 10
- IL_0022: ldloc.1
- IL_0023: ldftn instance void WindowsFormsApplication4.Form1/'<>c__DisplayClass1'::'<Form1_Load>b__0'(int32)
- IL_0029: newobj instance void class [mscorlib]System.Action`1<int32>::.ctor(object, native int) IL_002e: call valuetype [mscorlib]System.Threading.Tasks.ParallelLoopResult [mscorlib]System.Threading.Tasks.Parallel::For(int32, int32, class [mscorlib]System.Action`1<int32>)
- IL_0033: pop
- IL_0034: ldloc.0
- IL_0035: callvirt instance void [System]System.Diagnostics.Stopwatch::Stop()
- //注意,Sleep已經(jīng)不在Load方法中了,而是被一個(gè)“b__0”代替,并行代碼與宿主代碼分離,以下就是b__0的
- IL: .method public hidebysig instance void '<Form1_Load>b__0'(int32 i) cil managed
- {
- // 代碼大小 26 (0x1a)
- .maxstack 8
- IL_0000: nop
- IL_0001: ldarg.0
- IL_0002: ldarga.s i
- IL_0004: call instance string [mscorlib]System.Int32::ToString()
- IL_0009: stfld string WindowsFormsApplication4.Form1/'<>c__DisplayClass1'::a IL_000e: ldc.i4 0xc8
- IL_0013: call void [mscorlib]System.Threading.Thread::Sleep(int32)
- IL_0018: nop
- IL_0019: ret
- } // end of method '<>c__DisplayClass1'::'<Form1_Load>b__0'
結(jié)構(gòu)圖:
以上的紅色代碼就是在Code A中出現(xiàn)的主要代碼。再讓我們重溫一下這張圖,IL的代碼任務(wù)已經(jīng)很明顯的指示了出來(lái)。
每當(dāng)我們?cè)黾右粋€(gè)并行代碼段,IL中就會(huì)增加一個(gè)b_N塊:假如我們的代碼中包含兩個(gè)Parallel塊,每塊的主代碼與上述一致,IL如下:
- IL_0019: callvirt instance void [System]System.Diagnostics.Stopwatch::Start()
- IL_001e: nop
- IL_001f: ldc.i4.0
- IL_0020: ldc.i4.s 10
- IL_0022: ldloc.1 IL_0023: ldftn instance void WindowsFormsApplication4.Form1/'<>c__DisplayClass2'::'<Form1_Load>b__0'(int32)
- IL_0029: newobj instance void class [mscorlib]System.Action`1<int32>::.ctor(object, native int) IL_002e: call valuetype [mscorlib]System.Threading.Tasks.ParallelLoopResult [mscorlib]System.Threading.Tasks.Parallel::For(int32, int32, class [mscorlib]System.Action`1<int32>)
- IL_0033: pop
- IL_0034: ldc.i4.0
- IL_0035: ldc.i4.s 10
- IL_0037: ldloc.1
- IL_0038: ldftn instance void WindowsFormsApplication4.Form1/'<>c__DisplayClass2'::'<Form1_Load>b__1'(int32)
- IL_003e: newobj instance void class [mscorlib]System.Action`1<int32>::.ctor(object, native int) IL_0043: call valuetype [mscorlib]System.Threading.Tasks.ParallelLoopResult [mscorlib]System.Threading.Tasks.Parallel::For(int32, int32, class [mscorlib]System.Action`1<int32>)
- IL_0048: pop
- IL_0049: ldloc.0
- IL_004a: callvirt instance void [System]System.Diagnostics.Stopwatch::Stop()
下圖中會(huì)有對(duì)應(yīng)模塊出現(xiàn):
上面的例子說(shuō)明,在IL階段已經(jīng)為運(yùn)行時(shí)的并行執(zhí)行任務(wù)做了準(zhǔn)備,編譯階段將并行任務(wù)從宿主中分離出來(lái),運(yùn)行階段決定是否采用并行方式執(zhí)行任務(wù)。
【編輯推薦】
- 3.9.3 云計(jì)算與并行計(jì)算
- 1.4 商業(yè)應(yīng)用的并行計(jì)算
- 1.3 網(wǎng)格計(jì)算:分布式并行計(jì)算
- 并行計(jì)算的難點(diǎn)與數(shù)學(xué)原理解析