误区三 . 并行计算是运行时的事

的确,DotNet会在运行时决定是否使用并行库处理代码,但是早在你编译代码时,编译器就早已为这一时刻做好准备,换就话说:

1. 使用并行库处理代码与普通方式对比,IL的结构是不同的。

2. 即使你选择使用并行计算,并且你也确实拥有多核(线程)CPU,运行时你的代码也不一定是并行的。

使用TPL后CLR可能会分解任务,这一依据的其中之一是由IL支持的,IL将并行的任务代码分离,以便在将来的操作中并行,这一点可以从以下的示例中看出来,以下两段示例的核心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是直接出现在Load方法中的。

再来看看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已经不在Load方法中了,而是被一个“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'

结构图:

以上的红色代码就是在Code A中出现的主要代码。再让我们重温一下这张图,IL的代码任务已经很明显的指示了出来。

每当我们增加一个并行代码段,IL中就会增加一个b_N块:假如我们的代码中包含两个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()

下图中会有对应模块出现:

上面的例子说明,在IL阶段已经为运行时的并行执行任务做了准备,编译阶段将并行任务从宿主中分离出来,运行阶段决定是否采用并行方式执行任务。

 误区三 . 并行计算是运行时的事

的确,DotNet会在运行时决定是否使用并行库处理代码,但是早在你编译代码时,编译器就早已为这一时刻做好准备,换就话说:

1. 使用并行库处理代码与普通方式对比,IL的结构是不同的。

2. 即使你选择使用并行计算,并且你也确实拥有多核(线程)CPU,运行时你的代码也不一定是并行的。

使用TPL后CLR可能会分解任务,这一依据的其中之一是由IL支持的,IL将并行的任务代码分离,以便在将来的操作中并行,这一点可以从以下的示例中看出来,以下两段示例的核心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是直接出现在Load方法中的。

再来看看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已经不在Load方法中了,而是被一个“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'

结构图:

以上的红色代码就是在Code A中出现的主要代码。再让我们重温一下这张图,IL的代码任务已经很明显的指示了出来。

每当我们增加一个并行代码段,IL中就会增加一个b_N块:假如我们的代码中包含两个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()

下图中会有对应模块出现:

上面的例子说明,在IL阶段已经为运行时的并行执行任务做了准备,编译阶段将并行任务从宿主中分离出来,运行阶段决定是否采用并行方式执行任务。

本文转自Aicken(李鸣)博客园博客,原文链接:http://www.cnblogs.com/isline/archive/2011/04/21/2023137.html,如需转载请自行联系原作者

DotNet并行计算的使用误区(二)相关推荐

  1. 雅思做题技巧误区一,不敢选TRUE。误区二,见到only或must等绝对词就选FALSE。误区三,找不到就选NOT GIVEN。误区四,喜欢把TRUE/FALSE/NOT GIVEN理解为

    目录 误区一,不敢选TRUE. 误区二,见到only或must等绝对词就选FALSE. 误区三,找不到就选NOT GIVEN. 误区四,喜欢把TRUE/FALSE/NOT GIVEN理解为" ...

  2. 并行计算之MPI(二)

    1.并行编程模型 目前两种最重要的并行编程模型是数据并行和消息传递数据并行编程模型的编程级别比较高编程相对简单但它仅适用于数据并行问题消息传递编程模型的编程级别相对较低但消息传递编程模型可以有更广泛的 ...

  3. dotnet Core学习之旅(二):安装IDE

    [重要:文中所有外链不能确保永久有效] >开发工具 高效的开发必然需要一个优秀的集成开发环境(IDE) 对于.NET Core 2.x可以使用包括但不限于以下IDE来进行开发. Visual S ...

  4. Java新手会遇到的三大误区,一定要避免!

    很多学习java技术的学员都是零基础学员,之前对java技术一点都不了解,所以java新手在学习java技术的时候很容易进入误区,下面小编分享的Java新手会遇到的三大误区,一定要避免! 作为目前最为 ...

  5. 对于SD-WAN安全的5个误区

    误区一:不了解方案架构就用 SD-WAN解决方案对于企业市场来说仍然较新,因此许多企业对SD-WAN的方案架构可能并未吃透,便急于项目上马,为安全威胁埋下了隐患.因此,选择具有符合企业特定需求的安解决 ...

  6. 智慧城市建设中的五个误区和四大难点

    当前,随着社会的进步,信息技术与工业.农业.社会等各个方面的全面融合发展阶段.这种深度融合又直接反映在城市的快速发展上,反映在城市建设快速向智慧化道路上的进展.建设智慧城市已经成为当今世界城市发展的趋 ...

  7. 有关容器的六大误区和八大正确场景

    作者:刘超,目前在网易从事云计算和大数据架构工作,在工作中积累了大量运营商系统,互联网金融系统,电商系统等容器化和微服务化经验. 来自:刘超的通俗云计算 做容器的研究和容器化几年了,从最初对于容器的初 ...

  8. p8工程师告诉你软件测试的三大误区,你误了几个?

    纵观软件测试行业的发展史,相信很多人都知道它是伴随着"软件"而出现的. 在早期软件开发的过程中,"测试"的含义其实是比较狭窄的,测试这一行为也完全由开发人员执行 ...

  9. 只开窗不镀锡_平开窗选购时有哪些误区

    选购平开窗时,如果不了解它的性能以及材质的话,容易走进一些误区.那平开窗选购时有哪些误区?PChouse带大家一起了解下吧. 误区一.重厚度 铝合金平开窗选购符合国家相关规定要求的即可,门窗的铝型材壁 ...

最新文章

  1. matlab中cell用法
  2. Java接口interface
  3. Flask项目支持https
  4. Nebula3的Input系统
  5. zigbee绑定 使用_遇见-果加智能锁F2——使用体验
  6. 搜索旋转排序数组—leetcode31
  7. Linux mmap
  8. python小括号、中括号和大括号的区别
  9. Oracle财务系统常用标准报表
  10. HDU today(最短路径)
  11. RTI_DDS自定义插件开发 1
  12. OSPF路由协议实验配置命令
  13. 数学建模MATLAB之分析法(一)
  14. ubuntu18.04 ros-melodic 中科大的ROS教程gazebo打开没有地图与环境,只有地板
  15. miRNA 在基因调控中的作用
  16. 带参数的公众号二维码 生成+后台拦截java
  17. NOIP2020游记
  18. VMware配置虚拟机网络
  19. Quartz系统来源分析-幽默风趣
  20. win10设置虚拟内存_大内存时代,电脑系统还需要设置虚拟内存吗?

热门文章

  1. pythontuple数据类型_Python基础教程2d–数据类型-tuple(元组)
  2. oracle exp导出分区表,【实验】【PARTITION】exp导出分区表数据
  3. 四路服务器芯片组,四路服务器主板配置
  4. Redis的学习记录
  5. 电路的静态与动态特性
  6. 智能车竞赛,AI视觉组赛题浅析
  7. 第十五届全国大学生智能汽车竞赛赛道拼装图
  8. 什么?欧洲也有个恩智浦杯?
  9. 后宫佳丽三千,皇后只有一个
  10. java 并发包学习_Java学习笔记—多线程(java.util.concurrent并发包概括,转载)