# 克里斯·拉特纳：计算与编程语言的未来

> 从 LLVM、Swift 到 MLIR，聊编译器设计、编程语言演进，以及硬件与软件协同的未来。

- 原标题：#131 – Chris Lattner: The Future of Computing and Programming Languages
- 期数：第 131 期
- 发布日期：2020-10-18
- 嘉宾 / 主题：克里斯·拉特纳
- 网页版：https://lexfridman-cn.pages.dev/ep/chris-lattner-2/
- 官方页面：https://lexfridman.com/chris-lattner-2/
- 精读字数：约 7613 字（阅读约 17 分钟）

> 本文为 lex.qiaomu.ai 基于原始访谈的 AI 改写中文精读，非官方翻译；引用请注明出处并链接网页版。

Chris Lattner 在 2000 年读大学时开始写 LLVM。这个项目后来变成了苹果、Google、以及几乎整个现代编译器世界脚下的地基。二十年后，他亲手搭起来的这套基础设施，在他眼里已经变成了需要被打破的对象。

他给出的理由很直接：LLVM 社区里有一批人已经在这个项目上工作了十年。十年是很长的时间。长到你开始看不见手里这件东西的毛病。他觉得这个社区正在走向僵化，需要新的项目进来搅局。他自己造的那个新东西叫 MLIR，现在已经挂在 LLVM 的伞下，但老一代 LLVM 开发者对它并不熟悉，于是"新的东西不可信"这种文化反应就出现了。

一个造了轮子的人，回头说轮子该换了。这期播客里他聊的东西远不止编译器：编程语言该怎么设计、指令集为什么要开放、摩尔定律到底死没死、并发模型该怎么写进语言、GPT-3 会不会改写编程、疫情之后硅谷会变成什么样。下面挑几条最有信息量的线索展开。

## 三个老板，三种带人的方式

访谈开场问的是 Steve Jobs、Elon Musk、Jeff Dean 各有什么过人之处。Lattner 跟 Elon 共事的时间比跟 Jobs 长得多，所以他做了个分组对比。

他的判断是：Jobs 更关注人的因素，Musk 更关注技术本身。

> "Steve 想造的是让人喜欢、影响人生活的东西，他会往前面看一点，去看人们想要什么。Elon 更关注指数级增长的规律，去预测技术会怎么发展，而且他花大量时间和工程师泡在一起。"（Chris Lattner）

关于 Jobs 怎么让设计师跟工程师对话还赢得尊重，Lattner 的观察是，Jobs 推人推得很狠，但一旦对方给出了让他信服的解释，他就会放手。他对工程本身是尊重的，同时他又知道什么时候该继续压。读人读得准，你就知道对方是不是留了余力，还能不能再榨出一点东西。这是一种很难教的能力。

Jeff Dean 被归到完全不同的类别。Lattner 说他是个非常好的人，是典型的 Google 文化，希望身边的人都开心，同时又极其聪明，能把人聚起来。**Jeff Dean 到今天还在写代码。**他通过技术本身、通过自己动手去领导，然后把别人拉进来、激发他们。Lattner 说他甚至不觉得 Jeff 会想当 CEO 那种角色。

这三个人放在一起看，领导力没有统一答案。要看你面对的是什么时间、什么地点、什么问题。

## 不知道答案，不代表你没资格带队

Lattner 说他随着经验增长，越来越舒服的一件事是"接受自己不知道"。

> "领导力很大一部分跟'你有正确答案'无关，跟'你能拿到正确答案'有关。"（Chris Lattner）

他讲了一个具体的操作：在团队里营造一种环境，别搞自上而下的"我让你做什么你就做什么"，鼓励每个人都参与解决方案，并且提供一个安全的空间，让下属在你做错的时候敢开口告诉你。

他自己在船业公司待过一段时间，对船怎么设计几乎一无所知。结果发现只要肯问大量看起来很蠢的问题，变聪明的速度会非常快。前提是周围有一群愿意教、也愿意自己学的人。

这条经验贯穿了他整期播客。后来谈到疫情、谈到远程工作、谈到怎么学习新语言，他反复回到同一个点：**把自己放进一个周围人都比你懂的环境里，然后问蠢问题。**聪明人通常喜欢教别人，你只要准备好听，准备好成长，就能做出一些别人想不到的连接。

## 编程语言是思维的自行车

这是整期播客里最值得记下的一句。

> "你可以走路，但你骑上自行车会快得多。编程语言就是思维的自行车。"（Chris Lattner）

他借的是 Jobs 那句"计算机是思维的自行车"，但把它挪到了语言本身。逻辑是这样的：计算机擅长做特定的事，而人脑里有一个想法，想让它实现。从直接写汇编，到高级抽象，到设计一个神经网络让机器替你干活，中间有无数个层次可以停。停在哪里，就决定了你得到什么、付出什么。

这里有个值得记住的判断：**编程语言有两条腿，一条是底层的机械部分，类型系统、编译器、怎么让计算机高效跑起来；另一条是 UI，也就是语言和人之间的界面。**后面这条很多人不当回事，觉得无非是花括号、分号、空格还是 Tab，纯主观偏好。但 Lattner 坚持，UI 是一个设计问题，而且好的设计和坏的设计，人是能感觉出来的。

他的例子是 Swift。Swift 在底层有一堆好东西，同时在让代码"感觉良好"这件事上投入了巨大的人力。这不是玄学。

具体怎么让语言感觉良好？他给了一套很实用的判断标准。

- 样板代码太多，你会觉得自己没在产出，这是坏事
- 内存不安全，你会被悬空指针和各种 bug 缠住，调试到怀疑人生，这也是坏事
- 把这些东西从体验里减掉，用户就会更开心

但这里有个陷阱。Stack Overflow 上那些高票答案，代表的是一小撮最活跃用户的优先级：安全的代码、规范的代码、稳定的代码。这不一定跟大多数普通用户的体验吻合。如果 99% 的人只关心"我想搭个 Web 服务器把事办了，多快能办成"，那么语言设计者就要清楚自己到底在为谁优化。

所以语言设计真正要回答的是两个问题：**有哪些库已经存在，以及你能多快把它们拼起来。**语法层面的争论，在用户到达目标的过程中只占很小一块。

## 值语义：同时解决正确性和性能的那个甜点

这是技术含量最高的一段，值得慢慢拆。

Lattner 用 Tensor（张量）举了个例子。Tensor 就是一个多维数字网格，能做加减之类的运算。为什么在 Python 里你有时候必须显式 clone 一个 Tensor？

原因是 Python 用的是引用语义。你手里握着的是一个指针，它指向那个东西，你并没有直接持有它本身。你把 Tensor 传给一个函数，函数在里面加了点东西，你回到外面一看，发现它也变了。更麻烦的是，你把 Tensor 交给某个对象，它把引用存进了字典里，之后又往里塞数据。你以为你只交出去一份，对方以为自己是唯一的持有者，谁也不知道背后发生了什么。于是你只能 clone，因为你不确定自己是不是唯一持有者。

做机器学习、习惯用数学思维思考的人，会觉得这很反直觉。数学里对象是按值传递的，Python 却安静地不这么干。等你 debug 到一半，才发现要搞清楚克隆发生在栈的哪一层，还得先读懂那个库的实现。这就是纯粹的时间损耗。

Swift 用值语义解决了这个问题。

> "在 Swift 里，Tensor 是一个值。你复制它，就看起来得到了一份独立的拷贝。你改其中一份，另一份不会跟着变，因为你只是复制了它。"（Chris Lattner）

听起来像每次操作都要付一次拷贝的代价。但 Swift 用了 copy-on-write：你传一个数组给函数，函数如果只是想读，大家共享同一份内存；只有当某一方真的要改，系统才真正复制。传出去的时候，如果只有一个引用，系统就知道可以就地更新，不用额外分配。

对比 Java。Java 的字符串是不可变的，所以每次拼接都要分配一个新的对象来装 x+y，因为别人可能还持有原来那个的指针。不可变性带来的安全，代价是性能。纯函数式语言在大量场景下都是这个模式。

Swift 的赌注是：**把值语义做成默认，同时用 copy-on-write 拿回性能，可以得到一个其他语言里没见过的甜点区。**

这个设计还有个更深的意图。它让数学在代码里真的像数学一样工作，同时又保留了程序员需要的底层效率。你不会为了正确性牺牲性能，也不会为了性能天天怀疑自己手里的是不是唯一引用。

这就是"渐进式披露复杂性"的一个实例。Swift 允许你从 print("hello, world") 开始，不必一上来就写 public static void main 加一堆访问控制、包、类。你正常写代码，默认是安全的、够快的。等你成了高级用户，想控制底层指针，可以去调 malloc，但没人会在第一页教程里教你这么干。这种分层的能力，是 Lattner 认为编程语言设计里最难也最有价值的部分。

## 语法糖之争与一场卸任

访谈里有一段关于 Python 3.8 引入 Walrus 操作符（海象操作符）的讨论，非常有意思，因为它不只是技术问题。

Lattner 先定义了什么算语法糖：把一个语言里已经存在的东西，用一种更简洁的方式写出来。他随即指出，这种特性最大的麻烦在于，它的价值几乎完全落在主观区间里：**这件事发生的频率到底高不高，值不值得为它引入新语法？**

他给了一个人类心理学的观察。面对一个新东西，人们会系统性地高估学习它的负担。它看起来很陌生，所以你抗拒。但如果它从一开始就在语言里，你就会说"这当然是 Python 的一部分，我熟得很"。

Walrus 操作符引发的争议最终导致 Guido van Rossum 卸任了 BDFL（终身仁慈独裁者）的位置。Lattner 对这件事的解读，视角比一般人深。

> "我从中得到的感受是，他把决策者的重量压在了自己肩上，而且这件事和他人身份认同绑得太紧，所以他把它当成私人的事。他把自己放在了'那个人'的位置上，周围却没有一个支撑结构。"（Chris Lattner）

他的类比很妙：创始人知道公司是怎么一步步走到今天的，所以敢说"我们过去二十年都这么干，但今天我们换个活法"，然后推动整个公司转型。但创始人走了之后，继任者往往不敢做这种决定，哪怕 CEO 理论上什么都能干。

原因有两个。

第一个是继任者没经历过那些决策的过程，不知道当初的决策依据是什么。一旦原则变了，你本该有义务改变做法、改变方向。但如果你不知道当初是怎么走到这一步的，那一切就像福音书，你不会去质疑它。

第二个更狠：**即使你在理论上是大权在握的那个人，你也只是"自以为在掌权的人"。**你得去激励团队，得解释、得让人理解、得让人真心认同。如果他们不信，方向就转不过来。领导者能行使的权力，是有上限的。

Swift 的做法是用一个核心团队来分摊这份重量，最终决策交给群体的智慧。这让决定不那么私人化，而且有公开的提案流程和决策理由记录。Lattner 把这种机制类比成最高法院的判例法：每次决定都有据可查，既能指导未来的讨论，又能充当一种防御机制。有人不满的时候，矛头指向的是"这个决定"，跟"某个人做错了事"脱钩。

他也承认这个模式不完美。核心团队的每个人都是不同的人，观点不一样，还有 Apple、Google、SiFive 三个组织在里面。但正因为如此，从原则出发推导决定，再想办法让社区理解并认同，这条路才格外重要。

## LLVM 的二十年之痒，和 MLIR 的野心

LLVM 到 2020 年 12 月就满二十岁了。Lattner 说这个项目正处在容易钙化的年纪。

他的原话里有一层很微妙的自省。他说自己的毛病是能看到 LLVM 的很多问题，这些问题一直硌着他，但他没时间去修。时间久了，它们像指甲缝里的沙子，你摆脱不掉。而别人看不到这些问题，也抗拒改变，于是"我们应该修这个"换来一句"听起来风险很大"。

他提出了一个新框架：MLIR（Multi-Level IR）。名字是编译器圈的人取的，取名水平堪忧，Lattner 自己都吐槽了。

MLIR 要解决的是什么问题？编译器历史上都是为某个特定领域造一整套工具。LLVM 擅长 CPU，JVM 擅长垃圾回收语言加动态编译，每个领域都从头造一遍，大量的东西重复实现。

MLIR 提供一套通用的编译器基础设施，让你能更快地为不同领域造出专用的编译器，而且结果质量还不错。它比 LLVM 更通用、更灵活，LLVM 反而是它的一个子集。目标领域包括自定义加速器、矩阵乘法硬件，以及一整个硬件综合的世界，也就是用来设计电路的编译器，编译的领域是晶体管。

这里有个关于社区文化的绝佳观察。**MLIR 是由 Lattner 和一帮非常了解 LLVM 的人造的，所以他们修掉了 LLVM 里的一堆历史错误。但那些二十年来一直在维护 LLVM 经典部分的人，对新东西并不熟悉。新东西感觉上就是"不可信"的。**

他没有为此愤愤不平。他觉得这种文化张力是健康的。思想会渗透，技术会扩散，人需要用自己的语言去重新理解一件事。这个过程很慢，但它在发生。

## RISC-V：把指令集从公司手里拿出来

Lattner 现在在 SiFive 做平台工程的高级副总裁。这家公司由 RISC-V 的三位创始人建立，其中就有 Dave Patterson。

RISC-V 的核心特征是：它是一个开放标准。x86 只能由 Intel 和 AMD 造，ARM 的指令集只能由 ARM 公司授权出去，MIPS 归某家公司所有再授权。RISC-V 谁都能拿来造芯片。

这听起来抽象，但它解决的是一个非常现实的问题。过去几十年里，公司起起落落，指令集也跟着起落。Sun 的 SPARC 活到了今天，HP 的 PA-RISC 曾经承载了整个服务器业务和大量客户，后来 HP 决定转向 Intel 的 Itanium，结果并不好。

真正的问题在这里：**你在一个由某家公司拥有的指令集上投入了巨额资金、大量工程和软件工作，围着它建了一堆产品，然后这家公司做了个技术决策或者商业决策，你就卡死了。**哪怕强如 Intel，也不能保证每次都执行到位。

RISC-V 提供的是可选性。你从 SiFive 买一个实现，如果二十年后 SiFive 出了什么问题，没关系，你可以从别人那里买 RISC-V 核。整个生态里有人在造不同权衡的核。你有产品家族、有多种需求，大概率能在 RISC-V 空间里找到合适的东西。

Lattner 的展望是：**未来会出现大量定制芯片。**眼下的局面是，一家做智能硬件的公司如果没有 iPhone 那样的出货量，就负担不起定制芯片，只能买别人设计的、并不完全贴合自己需求的现成货，为用不上的硅付钱。如果设计芯片的成本降下来，定制芯片就会变多，电池续航会更好，方案会更贴合具体场景，上市速度会更快。

## 摩尔定律：三种解读，都没错

访谈里把 Dave Patterson、Jim Keller 和普通人对摩尔定律的理解摆在一起。

Jim Keller 说物理上还有上千倍的空间，晶体管还能更小更快。Lattner 认为他说得完全对，我们还没撞到物理极限。但那不是摩尔定律本来的意思。

摩尔定律的原始表述里有一个明确的经济维度：单位面积的成本，以及那个空间里最经济的点。Dave Patterson 常强调的正是这一点。按这个技术性的定义，摩尔定律确实变了。

Lattner 又给了第三种解读：单线程性能不再像以前那样提升了。以前你买一颗奔腾 66，前一年是奔腾 3，性能翻倍，而且是在做完全相同的事情时翻倍。同样的程序跑快一倍，你只要开张支票等一年半。很多人心里的摩尔定律就是这个，而这个已经死了。

取而代之的是什么？是逼着人换编程方式。你得写 CUDA 才能拿到 GPU 算力。你得习惯一台机器上有 50 个核、100 个线程。你有专为机器学习做的加速器。性能还在，但你得改编程模型。

而一旦谈到改编程模型，就绕回语言问题了。C 语言是为 CPU 设计的，想跟 GPU 说话，你得去用它的表亲 CUDA，那是一套不同的工具、不同的世界、不同的思维方式。现在还没有一个能统一缩放的世界，Lattner 觉得可以有一个，而且会好得多。

## 让并行成为语言的一等公民

聊到机器学习为什么能自动并行，Lattner 指出了一个漂亮的转折。

让一个 C 编译器或 Swift 编译器自动并行化命令式代码，还要推理所有指针，是非常难的问题。但换到机器学习的领域，那些做猫检测器的人，顺手搞出了一个极其强大的抽象层：一组可以拼装的算子。抽象层次被抬得足够高，自动并行化的编译器就突然可行了。你可以用 TensorFlow 写一个模型，让它在 1024 个 TPU 节点上跑。

> "这套东西出自那些只想解决问题的人，加上社区的有机演化，编程语言圈的人并没有参与。"（Chris Lattner）

批量处理（batching）也是同一个道理。一个很朴素的想法，但威力巨大。

他自己写的《Swift 并发宣言》是另一种思路。写宣言的原因是，Swift 社区需要小而精细的提案，一次只推进一小步，但同时又需要大的方向。当你在做一件大事却要拆成小步走的时候，怎么知道不是在随机游走？宣言就是那个把大图景画出来、让后续的小步有参照的东西。

宣言里的核心思路有几层：

- 多个计算机或多个线程通信时，最好是异步的。所以要能分别运行，再互相通信，这意味着需要建模异步通信的机制，比如 async/await
- 往上一层是内存安全。两个线程同时碰同一块内存就是竞态条件，这种 bug 让人抓狂，因为通常无法复现。值语义在这里又派上用场，因为数学和拷贝在并发世界里同样成立
- 再往上是给程序员的心智模型。宣言提出的方案是一个老模型的新版本：actor。逻辑上，你写的是一块单线程的孤岛，它跟其他东西异步通信
- 继续往上，这些异步通信的东西不共享内存，那它们为什么必须在同一个进程里？可以跨进程，可以跨机器。于是你得到一条通往分布式编程的平滑路径
- 再往上，加速器本质上是异步的东西，你通过发消息跟它通信。怎么给它们编程，这就很有意思了，而且不在提案范围内

这里有一个贯穿全篇的设计哲学问题：**多少该是魔法，多少该交给人控制？默认情况错了的时候你怎么办？**

Lattner 举了 Logo 作为反面例子。很好上手，专为教小孩设计，但你很快会撞到天花板，上不去了。只能换一个世界，重写所有代码。Python 的并发也有类似的困境：全局解释器锁让多线程很麻烦，你写了一定规模的程序之后，会发现自己被一系列糟糕的权衡困住。

他的偏好很明确：**建一个能讲清楚的简单模型，同时留一个逃生舱。**Swift 里默认你按标准写法写就不会踩坑，但如果你非要拿一个 C 级别的指针，可以显式去做。默认有护栏，护栏外有通道。

至于谁来决定代码的哪部分并行？在他的提案里是程序员。运行时和编译器要非常可预测。这跟历史上那批试图自动并行化的编译器形成对比。

那些编译器项目很有诱惑力：不改一行代码，换个编译器就快十倍，编译器会做模式匹配、深度分析，把结构体数组转成数组结构体之类的。麻烦的是，你加个功能、重构一下代码，突然性能掉了十倍。因为某个函数没被内联，你触发了编译器的某个启发式失效。

> "作为用户，你不想知道，你不想知道编译器怎么工作、内存层次怎么工作、它怎么被并行化的。你希望这些被抽象掉。但一旦魔法失效，你就掉下悬崖，不知道该怎么办。"（Chris Lattner）

如果你在乎性能，可预测性就极其重要。

## GPT-3 和 Software 2.0 的边界

Lattner 对 GPT-3 的反应分两面。一面是，把模型做大、把数据塞得更多，只要训练方法对、架构好，结果就更好，这在深度学习圈早就被理解透了，所以 GPT-3 本身不算意外。另一面是，让它真正跑起来需要海量的工程投入。

他提到 OpenAI 那篇引发讨论的博客：因为担心被滥用造成社会伤害，所以不发布。他认为这个担忧至今成立。用意良好的工具可以被用在很可怕的地方，影响可以非常深远。

关于 Andrej Karpathy 提出的 Software 2.0，也就是用学习模型替代越来越多的命令式代码，Lattner 的态度是：**部分同意，但他把它看作一种新的编程范式，跟 Software 1.0 是并列关系，谈不上替代。**

他给了一套很清晰的判断。机器学习解决某几类问题极其出色，而且是唯一正确的方式：

- 你不会再用 C 代码去写一个猫检测器你不会再用 C 代码去写一个
