历史是那些本可以避免的事情的总和。
康拉德·阿登纳
你已经读完了这本书,干得好!我希望你的旅程是愉快的、充满挑战的和值得的。
对于编辑和撰稿人来说,这是第二版的终点,但对于那些愿意加入的人来说,这也是第三版的起点。无论如何,回顾一下过去的旅程是很好的。
第1章介绍了本书的内容,以及对那些对低级并行编程以外的其他内容感兴趣的人的一些替代方案。
第2章讨论了并行编程的挑战和解决这些挑战的高级方法,还讨论了如何避免这些挑战,同时仍然获得大部分并行的好处。
第三章对多核硬件进行了高层次的概述,特别是那些给并发软件带来挑战的方面。本章将这些挑战归咎于物理定律,而不是固执的硬件架构师和设计者。然而,硬件架构师和工程师可以采取一些措施,本章讨论了其中的一些方法。与此同时,软件架构师和工程师也必须尽自己的一份力来应对这些挑战,相关内容将在本书后续章节中讨论。
第4章简要介绍了低级并发交易的工具。
第5章演示了这些工具的使用,更重要的是并行编程设计技术在并发计数这一简单但令人惊讶地具有挑战性的任务中的应用。事实上,并发计数算法非常具有挑战性,因此许多并发计数算法被广泛使用,每种算法都针对不同的用例进行了专门化。
第6章深入探讨了最重要的并行编程设计技术,即在尽可能高的层次上对问题进行划分。本章还概述了该设计空间中的许多要点。
第7章阐述了并行编程的工作主力(和恶棍),锁定。
本章介绍了多种类型的锁定,并提出了一些工程解决方案,以解决许多众所周知且被大肆宣传的锁定缺陷。
第8章讨论了数据所有权的用途,其中同步是由给定数据项与特定线程的关联提供的。在适用的情况下,这种方法将出色的性能和可伸缩性与深刻的简单性结合在一起。
第9章展示了如何通过一点点拖延来显著提升性能和可扩展性,同时在许多令人惊讶的情况下还能简化代码。本章介绍的一些机制利用了CPU缓存复制只读数据的能力,从而绕过了物理定律的残酷限制。
限制光速和原子的微小。第10章讨论了并发数据结构,重点是哈希表,它在并行程序中有着悠久而光荣的历史。
第十一章深入探讨了代码审查和测试方法,第十二章概述了形式验证。无论你处于形式验证/测试的哪一边,如果代码没有经过彻底验证,它就不起作用。对于并发代码来说,这一点至少是双重的。
第13章介绍了一些情况,其中将并发机制相互结合或与其他设计技巧相结合可以大大简化并行程序员的工作。第14章探讨了高级同步方法,包括无锁编程、非阻塞同步和并行实时计算。第15章深入研究了至关重要的内存排序问题,介绍了技术和工具,不仅帮助你解决内存排序问题,还能完全避免这些问题。第16章简要概述了一个令人惊讶的重要话题——易用性。
最后,但绝对不是最不重要的,第17章阐述了关于未来的许多相互冲突的愿景,包括CPU技术趋势、事务内存、硬件事务内存、回归测试中形式验证的使用,以及长期预测并行编程的未来属于函数式编程语言。
但是现在我们已经回顾了这第二版的内容,这本书是如何开始的呢?
保罗的并行编程之旅始于1990年,当时他加入了Sequent计算机系统公司。Sequent采用了一种类似学徒制的项目,新招聘的工程师被安排在由经验丰富的工程师组成的隔间中,这些资深工程师指导他们,审查他们的代码,并就各种主题提供了大量建议。由于当时没有片上缓存,逻辑分析仪可以轻松显示特定CPU的指令流和内存访问,包括精确的时间信息,这使得一些新入职的工程师受益匪浅。当然,这种透明度的缺点是CPU核心时钟频率比21世纪慢了100倍。通过学徒制和硬件性能透明化,这些新入职的工程师在两到三个月内就成为了高效的并行程序员,有些人在几年内就开始了开创性的研究工作。
序列公司意识到,它能够迅速培训新工程师掌握并行计算的奥秘是不同寻常的,因此出版了一本精简的书籍,凝聚了公司的并行编程智慧[Seq88],这与几年前发表的两篇开创性论文[BK85,Inm85]相辅相成。已经深谙这些奥秘的人士对这本书和这些论文表示赞赏,但新手通常无法从中获益良多,往往会犯下极具创意却相当破坏性的错误,而这些错误并未被书或论文明确禁止。1当然,这种情况促使保罗开始考虑编写一本改进版的书,但他在这段时间的努力仅限于内部培训材料和已发表的论文。
到1999年IBM收购Sequent时,世界上许多最大的数据库实例都在Sequent硬件上运行。但时代变了,到了2001年,许多Sequent的并行程序员已将重点转向Linux内核。经过最初的犹豫,Linux内核社区热情而有效地拥抱了并发技术[BWCM+ 10,McK12a],带来了许多优秀的创新。
还有来自整个社区的改进。保罗时不时地想到要写一本书,但生活太快了,所以他没有在这个项目上取得任何进展。
2006年,保罗受邀参加了一个关于Linux可扩展性的会议,并获得了向尊敬的并行编程专家小组提出最后一个问题的机会。保罗开始提问时指出,在1991年至2006年的15年间,一个并行系统的成本已经从一栋房子的价格降到了一辆中档自行车的价格,显然在未来15年内,直到2021年,还有很大的降价空间。他还提到,价格的下降应该会带来更高的熟悉度和更快地解决并行编程问题的进展。这引出了他的问题:“到2021年,为什么并行编程还没有成为常规?”
第一位发言者似乎对提出如此荒谬问题的人相当不屑,迅速用简短的回答回应。对此,保罗也给出了简短的回应。他们来回争论了一段时间,例如,发言者的简短回答“僵局”引发了保罗的简短回应“锁定依赖检查器”。
这位专家最终没有更多的发言权,即兴说了一句最后的话:“像你这样的人应该用锤子敲打!”
保罗的回答当然是“你得排队等着!”
保罗把注意力转向下一位小组成员,这位成员似乎在赞同第一位小组成员和不愿面对保罗的一连串回答之间左右为难。因此,他发表了一段简短的、不置可否的讲话。小组剩下的时间里都是这样。
直到轮到最后一位小组成员发言,他是一位你可能听说过的名字叫林纳斯·托瓦兹的人。林纳斯指出,三年前(即2003年),任何与并发相关的补丁的初始版本通常都很糟糕,存在设计缺陷和许多错误。即使经过清理后被接受,错误仍然存在。林纳斯将此与2006年的现状进行了对比,他说当时并发相关补丁的第一个版本往往设计良好,几乎没有或根本没有错误。随后,他建议如果工具继续改进,那么或许到2021年并行编程将成为常规。
会议随后结束。保罗并不惊讶许多观众,特别是那些与第一位小组成员观点相同的人,对他避而远之。他也毫不意外地听到几位观众感谢他提出了问题。然而,当有位男士泪流满面地走上前来,几乎说不出话来地哭泣时,他感到非常惊讶。
你看,这个人曾在Sequent工作了几年,因此非常擅长并行编程。此外,他目前被分配到一个团队,负责编写并行代码。但进展并不顺利。你看,问题不在于他们难以理解他对并行编程的解释。
而是他们根本不听他的。
简而言之,他的团队对待这个人的态度与第一位小组成员试图对待保罗的方式相同。因此,在那一刻,保罗从“我总有一天要写一本书”变成了“我会尽一切努力写出这本书”。保罗不好意思承认他不记得那个人的名字,事实上,他可能从未知道过这个名字。
这本书毕竟是给那个人的。
这本书也适合那些想要将低级并发添加到自己的技能集中的其他人。如果你从这本书中记住的唯一一件事是图18.1中的教训,那就这样吧。
这本书也是对那位未具名的小组成员及其未具名雇主的一种致敬。几年后,这位雇主选择任命了一个更有用经验且言辞更少的人。这个人也曾是小组的一员,在那次讨论中,他直视着我说,平行编程可能比顺序编程难5%。
对于我们其他人来说,当有人试图向我们展示一个解决紧迫问题的方案时,也许我们至少应该对他们表示礼貌,倾听他们!