编写并行计算机程序的最佳方法是什么?常见的方法是让编译器将顺序程序转换为并行程序,或者使用并行语言或库编写并行程序。
在并行计算机的早期,并行编译器提供了诱人的前景,即在新兴的并行计算机上运行未经修改的“dusty deck”顺序FORTRAN程序。尽管对这些编译器的研究导致了现代编译器中使用的许多程序分析和表示创新,但产生的工具在并行大多数应用程序方面并不成功,开发人员转而求助于pthread和MPI等库。
在这种方法中,程序使用并行结构;要么显式并行操作,如fork-join,要么隐式并行操作,如map和reduce。理论上,这些抽象应该鼓励开发人员思考“并行”问题并编写并行程序,但实际上,即使使用它们,由于新的错误类型,如数据竞争和并行机器的多样性(例如,消息传递、共享内存和SIMD),并行编程也具有挑战性。
那么,开发人员如何在具有多核和向量处理单元的现代并行微处理器上提高其代码的性能呢?下面的文章提倡在开发人员和编译器之间进行有吸引力的分工,通过人工重构代码和数据结构,并强制并行执行一些循环,从而增加编译器生成和优化并行机器代码的机会。
这篇论文的结果是相当惊人的。对于11个计算密集型的内核,以这种方式开发的代码的执行效率平均只有最佳手工优化代码的30%,而且不需要开发人员使用低级编程结构或理解机器的体系结构和指令集。
但是为什么这种分工是必要的呢?为什么编译器不能并行化和向量化这些(相对简单的)程序?作者暗指“诸如依赖性分析、内存别名分析和控制流分析等困难问题”。在实践中,编译器使用大量的局部优化,每个优化增量地改进一小部分代码。改变程序计算结果的方式的大规模、普遍的重构超出了传统编译器的范围。直到最近在程序合成方面的工作,很少有关于探索可能转换的大空间的有效技术的研究。此外,即使是局部优化,保守的程序分析也会阻碍编译器的发展,因为保守的程序分析最多只能接近程序的潜在行为一个并且必须禁止可能对程序结果产生不利影响的优化。
下面的文章认为,当开发人员执行重构和注释时,应该成为现代计算机中每个程序员技能的一部分。
本文认为,由开发人员执行的重构和注释并不困难,应该成为现代计算机中每个程序员的必备技能。这些变化包括将结构数组转换为数组结构、阻塞循环以增加数据重用、注释并行循环以及采用更多并行算法。从概念上讲,这些变化都不难理解,尽管找到一种新的算法可能很有挑战性。然而,这些修改可能会在程序中引入错误,并且应用到大型应用程序时可能会很复杂,因为在大型应用程序中,一个数据结构可能由许多例程共享。
当然,程序优化通常也会对程序结构和可读性产生类似的有害影响,因此这些问题并不局限于并行程序。为了平衡直接编写一个正确的、高性能的并行程序的挑战,重构和注释似乎是一种产生可维护程序的合理方法。但是,如果生成的程序运行速度不能显著提高,那么这种方法就没有什么价值。
本文的主要贡献是证明了这种人力和编译器之间的分工实现了有效使用硬件并行来提高性能的目标。成熟的现代编译器通过重构和注释可以产生非常高效的并行代码。无论是编译器还是人们都不善于靠自己实现这一目标。
数字图书馆是由计算机协会出版的。版权所有©2015 ACM, Inc.
没有找到条目