并发编程中需要谨记的规则

  最小化临界区

  Amdahl定律和Gustafson定律都将并行算法中的顺序执行的工作视为性能问题的头号敌人。两个执行代码区段中间的时间需要顺序执行,这就是众所周知的临界值。在图1-16的分析Gustafson定律的图表中有四个这样的临界区。

  

  图 1-16

  当你并行化你的任务的时候,为了实现最好的性能我们需要最小化这些临界区。大多的时候,是难以避免并行执行区域之间的串行执行的代码的,因为需要加载并行任务和收集执行结果。然而,优化这些临界区域的代码并且移除不必要的代码比协调并行代码甚至更重要。

  当你面对一个拥有太多临街区域的执行计划的时候,要谨记Amdahl定律。如果你不能减少这些区域,那就尽力找到可以与这些区域并行执行的任务。例如,你可以提前取出要同时执行的并行代码需要的数据来提高解决方案的性能。谨记现在多核硬件提供的能力并避免总是想着你仅有一个执行单元。

  理解多核并发编程的规则

  James Reinders在Dr.Dobb’sJournal上发表了题为“多核并发编程的规则”的文章。他列举了八条规则来帮助开发人员进行多核编程。他的规则对使用C#和.NET 4编写的并行应用程序一样很有用。这些规则的描述如下

  1、并发编程的思想—这条规则就是要谨记并发编程思想进行设计,就像前边章节所提交的。

  2、面向抽象编程-你可以利用.NET4中的TPL提供的新特性使你的高层代码反映解决的问题,并且不是底层线程管理技术复杂化。第二章将会引入TPL。

  3、基于任务模型编程,而不是线程—TPL允许你你编写代码实现基于任务模型的设计而不用担心底层的线程。

  4、设计可以选择关闭并发—当你使用TPL写代码的时候,这些代码页可能会运行在单核的微处理器上。

  5、避免使用锁—利用新的类和方法、结构体解决对于复杂同步方式的需求是很重要的。TPL使避免在很多复杂的情景下使用重量级锁变得更简单,它提供了新的轻量级的同步方法。

  6、借助已有的工具和类库的帮助进行并发编程—Visual Studio 2010提供了新的工具调试、测试、协调并行代码。在本书中你将会学习很多相关的工具和类库。

  7、使用可伸缩的内存分配策略—TPL在CLR里提供了可伸缩的内存分配策略,当任务和线程执行的时候,它会自动的执行内存分配策略。然而,为了最大程度的利用缓存,你必须分析不同的分配可能性,并且尽力避免在每个任务里消耗过多的内存。

  8、设计的可伸缩性可以通过增加负载的方式实现—一旦你精通了并行扩展库,那么使用TPL提供的新的类考虑Gustafson定律就会很容易。如果你的设计需要具有很强的伸缩性,你将可以编写代码根据核心的增加进行调整。Windows 7 和windows Server 2008 R2支持多大256个硬件线程或者逻辑处理器;所以,有足够的伸缩性空间。

  为NUMA和更好伸缩性进行设计

  近年来,对多处理器支持的最广泛的模型是NUMA(non-uniform memory access)架构,而不是SMP(symmetricmultiprocessor)架构。SMP的一个最大的问题就是处理器总线会成为将来可伸缩性的瓶颈,因为每个处理器都拥有等同的能力方位内存和io。

  使用NUMA,于离得比较远的内存相比,每个处理器总是可以更快的访问离自己近的内存。当处理器的数目超过四个的时候,NUMA提供了更好的伸缩性。在windows的 scale-up-technology中,NUMA是以一下方式进行组织的,如图1-17

  一个单个的电脑或者机器可以有一个或者多个group。

  每一个group有一个或者多个NUMA节点。

  每个NUMA节点有一个或者多个物理处理器。

  每个处理器有一个或者多个物理核心,因为它经常是多核处理器。

  每个物理内核可以提供一个或者多个逻辑处理器或者硬件线程。

  

  图1-17

  图1-18展示了由两个NUMA节点构成一个group的计算机。每个NUMA节点有两个共享访问局部内存和io的两个处理器组成。如果NUMA节点0的处理器0的物理核心0的线程需要访问位于NUMA节点1的数据,则它必须使用两个NUMA节点之间的共享总线,这会比直接访问自己的局部内存要慢很多。

  

  图 1-18

  带有NUMA的计算机拥有多于一个的系统总线。每个特定的处理器集合使用自己可用的系统总线。同样的他们也访问自己自由的内存和io通道。就像前边描述的,他们可以使用合适的协调策略,使他们具有访问其他处理器的内存的能力。然而,很明显访问其他NUMA节点所有的内存要比方位自己NUMA节点内的付出的代价昂贵的多。

  NUMA的硬件需要特殊的优化。应用程序必须知道NUMA硬件和配置。我们可以执行那些需要访问NUMA节点的相同的内存的任务和线程模型。应用程序应该避免无效的内存方位,并且他们喜欢并发,考虑到内存的未知。

只要有信心,人永远不会挫败

并发编程中需要谨记的规则

相关文章:

你感兴趣的文章:

标签云: