传奇黑客看衰并行计算:多核处理器纯属浪费

阅读数:3041 2018 年 12 月 31 日

话题:文化 & 方法语言 & 开发硬件

AI 前线导读:
在购买电脑时,一般用户认为处理器核心越多越好,那么实际上是这么回事吗?或许是的,但问题是,你能真正充分利用这些核心吗?如果不能,那么花更多的钱买更多的核心岂不是浪费了?美国著名软件黑客、开源软件倡导者 Eric Steven Raymond 最近在一篇博文中表达了对计算机并行计算的质疑。他指出,单核处理器早已触及物理天花板,处理器厂商试图通过在单个芯片上放置更多的核心让用户误以为芯片很强大,但其实大部分软件无法充分利用这些核心。而对于一般用户来说,这些核心根本就是多余的,因为它们大部分时间什么都不做,只是在产生废热!

首先,让我们简单过一下这位大名鼎鼎的软件黑客的简历。

image

Eric Steven Raymond(简称 ESR),生于 1957 年,美国著名软件黑客(”黑客“并不都是贬义词,实际上,他是一名软件开发大神)和开源软件倡导者。他于 1999 年出版了经典著作《大教堂与市集》(英文名为 The Cathedral and the Bazaar,相信很多人都知道或看过这本书),这本书被誉为软件开源运动的“圣经”。他曾为单人角色扮演游戏 NetHack 编写过一本指南。他还是 Jargon File(面向程序员的术语字典,后来集结成册出版,也就是“The Hacker’s Dictionary”——黑客字典)的参与者之一。

以下内容翻译自 Raymond 的博文,文末附上了一些读者的精彩评论。

大规模并发和硬件并行计算是 21 世纪最性感的主题之一。从好的方面看,将图形处理单元(GPU)用在游戏和 AI 深度学习中确实取得了引人注目的效果——我们因此获得了大规模的硬件并行性。但令人遗憾的是,单核处理器的执行速度在 2006 年左右就已经达到了物理极限。漏电和热控问题严重限制了芯片时钟频率的增长,而传统的通过降低电压来绕过这一问题的方法现在面临着另一个问题——量子噪声。

作为权宜之计,硬件厂商在他们发布的芯片中放置更多的处理内核,并宣称他们的设备可以达到更高的理论总吞吐量。不过,硬件厂商也在努力尝试制造可以让程序员能够使用曲柄指令的串行单处理器,他们使用了管道化和推测执行技术,但其实这些技术仍然需要依赖并发性。

令人尴尬的是,很多不那么重要的计算工作负载无法很好地利用可见的并发性。原因有很多,在这篇文章中,我将描述其中的一些区别,希望能够帮助读者更好地思考这个问题。

首先,我们需要明确在哪些情况下可以轻松利用硬件的并行性以及为什么。我们对图形、神经网络、信号处理和挖掘比特币的计算进行了一番研究,然后找到了一种模式:要让并行化算法获得最好的效果,用来执行算法的硬件必须是专门为这些算法而设计的,而且除了运行这些算法外其他什么也不能做!

我们还发现,成功的并行算法(排序、字符串匹配、快速傅立叶变换、矩阵运算、图像反向量化等)的输入看起来都很相似。它们往往具有度量指标结构,而且数据的“近”和“远”之间存在隐含的区别,可以被分成不同的块,彼此远离的元素之间的耦合可以忽略不计。

在之前的一些有关局域性(locality)的文章中,并行方法似乎主要适用于数据具有良好局域性的情况。而且它们只有在专门为支持近距离元素通信而设计的硬件上才能获得最好的运行效果。

相反,在通用(冯·诺依曼体系)计算机上开发可用于有效分治处理具有不良局域性的输入的软件是非常困难的。

我们可以这么说:在某个问题上应用并行计算技术的几率与输入数据中不可约的非局域性程度成反比。

并行计算的另一个限制是一些重要的算法根本无法并行化。在我的另一篇博文中,我发明了“SICK 算法”这个术语,SICK 是“Serial, Intrinscally——Cope, Kiddo!”的缩写。针对这个术语,我可以举一些重要的例子:Dijkstra 的 n-least-paths 算法、有向图中的环检测、深度优先搜索、计算加密哈希链中的第 n 个项、网络流优化。

这些输入数据具有糟糕的局域性,尤其是在图结构和树结构中。加密哈希链无法被并行化,因为它们的项必须按严格的时间顺序进行计算——这对于验证链的防篡改来说非常重要。

这里有一个规则:如果存在 SICK 算法,就无法进行并行化。

除了这些,你还可能会遇到至少两种其他类型的情况,导致无法进行并行化。

一个是没有合适的工具可用。大多数编程语言只支持互斥和 mailbox 这两种通信方式,优点是原语很容易实现,缺点是暴增的复杂性会令人望而生畏,而且在达到四层交互锁时,人脑就几乎无法准确地进行模拟。

如果你足够幸运,或许可以从一些简单的原语集合中获得一些好处,例如 Go 语言通道(也就是通信顺序进程)或 Rust 的 ownership/send/sync 系统。但事实是,在冯·诺依曼体系计算机上,我们并不知道什么才是并行性的“正确”语言原语。也可能并不存在一个正确的原语集,或者也可能有两个、三个或甚至更多不同的原语集适用于不同的问题域。但就 2018 年的技术水平而言,没有人知道正确的答案。

最后,人类大脑的局限性也是个问题。即使是给定一个简单的算法、具有良好局域性的数据表示和一个强大的工具,并行编程对于人类来说仍然很困难。我们的大脑并不擅长对纯粹的串行程序的状态空间进行建模,而在并行程序方面就更加不擅长了。

因为有大量的现实证据表明,调试并行性代码对人类来说简直难如登天。由于不安全的操作顺序导致的竞态条件、死锁、活锁和隐含的数据损坏就是这方面最好的例子。

我认为,自从 Dennard Scaling(Robert Dennard 在 1974 年发表的一篇论文中预测说晶体管尺寸变小,功耗会同比变小)失效以后,了解这些限制就变得越来越重要。由于可以有效使用多个内核的代码存在这些瓶颈,一些多核硬件运行的软件永远无法充分利用所有内核。或者换一个说法,相对于其上运行的工作负载,硬件有点过度构建了。我们因此浪费了多少钱和精力?

处理器厂商当然希望你会高估多核心所能带来的功能增益,但他们是否能够从你身上榨取更多的钱来支付他们花在生产芯片上的高昂成本并仍然有获利空间?因此,他们加强力度进行市场营销,旨在分散用户的注意力,让他们不知道这些增益是不是真实的。

公平地说,在某些方面增益是真的。机架上的服务器每秒需要处理数十万个并发事务,对于这种情况,处理器核心数量与工作负载是匹配的。智能手机或嵌入式系统——对于这两种极端情况,需要付出很多努力才能最大限度地降低构建成本和功耗预算。

那么典型的台式机和笔记本用户呢?这个很难说,因为我们也看到了因为其他技术变化所带来的实际性能提升,例如使用固态大容量存储替代机械磁盘。而这些增益很容易被误认为是更多 CPU 吞吐量造成的。

以下是我的一些质疑:

  1. 对于大多数台式机 / 笔记本电脑用户而言,他们的电脑上唯一重度使用并行计算的是图形芯片。
  2. 两个以上的处理器内核通常会被浪费掉。操作系统可能可以在这些核心之间分配应用程序,但是这些应用程序通常无法真正利用多核并行性,并且大多数用户很少会同时运行足够多的应用程序来让所有核心饱和。
  3. 因此,部署在 4 芯及以上的机器中的大多数处理器单元大部分时间并没有在处理任务,而是在产生废热。

以下是读者针对 Raymond 博文发表的部分评论。大部分读者赞同作者的观点,也有少部分“有钱任性”的读者认为即使无法充分利用多核,那也不算浪费,因为说不定以后用得着呢。

Patrick3:

我总体上表示赞同。

我的电脑只在为建筑可视化执行 3D 渲染时才会让处理器达到 100% 的负载。

我发现,如果以美元为单位计算,现代“MegaDoomDestroyer”显卡速度甚至比 Threadripper 和 Skylake-X 这样的 1000 美元以上的 CPU 要快得多。渲染软件(Octane Render 和虚幻引擎 4)现在可以使用显卡来计算光照,也就是说,我在 CPU 上花 300 美元,再加上贵一点的显卡——总体速度就会比 CPU 快很多。渲染软件现在与计算机游戏技术非常相似,所以这个一点也不奇怪。

Dave:

我认为我的多核 CPU 工作场景现在很常见——比如虚拟服务器系统。我们在 6 台物理服务器上 24×7 运行差不多 50 个虚拟服务器。我们目前每台物理主机有 80 到 88 个物理核心,我们正在尝试能够达到 10%以上的利用率。我们还努力将 GPU 重度用户转到配备 NVIDIA GRID 系统的虚拟机。由于 RAM 配置的限制,我不认为我们会让这些系统达到 25%以上的核心利用率。

Chad Irby:

我完全同意“对于大多数台式机 / 笔记本电脑用户而言,他们的电脑上唯一重度使用并行计算的是图形芯片”这句话。

我们现在的硬件已经达到极限了。最新的 GPU,如 RTX 系列,对于标准游戏而言并不比以前的 GTX 型号快多少。唯一潜在的大加速是光线追踪(raytracing)——其中很大一部分是去噪,通过深度学习超级采样来实现,而后者依赖于将一些机器学习预处理交给 NVIDIA 超级计算机。

不可否认,大多数人不需要让四个或六个单独的核心都达到 99% 的负载,但有些人,比如像我这样的超级游戏玩家,会为了降低风扇噪音用冰水来给电脑降温。

一些游戏程序员开始真正使用多线程,因为他们必须找到一些方法,在机器的其余部分忙于与显卡通信时,保持游戏的智能,并顺畅地生成游戏地图。

Michael:
我完全赞同“应用程序通常无法真正利用多核并行性,并且大多数用户很少会同时运行足够多的应用程序来让所有核心饱和”这句话,但我认为它忽略了一些东西。
我非常希望多核桌面处理器能够让所有非 UI 进程在后台运行,并让 UI 空间对我的点击和击键操作做出超级快的响应。这样的话,我就不会在乎系统的内核是否过度配置或者是否浪费了算力。(例如,当 i5 甚至 i3 可以满足我的需求时,我还是买了 i7)。因此,使核心饱和大多数时候并非我们的目标。
但问题是,实际情况并不是这样的。我甚至无法分辨 WIMP 界面的响应速度是否比 15 年前更快。

Bret:

“部署在 4 芯及以上的机器中的大多数处理器单元大部分时间并没有在处理任务,而是在产生废热”——话是这么说,但那又怎样呢?

如果只是使用所有处理器的一小部分时间,就已经很值了。

多核通常意味着更快的编译和构建。即使 200 美元 / 小时(成本)的程序员只使用一小部分时间用于编译 / 构建,额外的 CPU 和电力成本也很快能收回。

例如,我为农业应用构建机器人,在 95%以上的时间里,核心平均利用率低于 50%。但如果在很短的时间内平均利用率接近 100%,应用程序就会出现故障,并且无法使用。而这些应用程序其实可以直接使用所有的内核。

即使计算机不能物尽其用,那又怎样?我们浪费的无非就是几百美元,但未来可能可以用到它们。在我看来,潜在的有用性并不算是很大的浪费。

英文原文:Pessimism about parallelism