词法作用域与动态作用域:为什么这个六十年前的设计抉择至今仍在影响你的代码

1975年,麻省理工学院的 Gerald Sussman 和 Guy Steele 正在开发一门新的 Lisp 方言。他们遇到了一个看似简单的问题:当一个函数引用外部变量时,它应该找到哪个值?这个问题困扰了编程语言设计者十五年,而他们的解决方案——采用词法作用域——后来成为现代编程语言的标配。 ...

15 min · 7062 words

GPU的SIMT执行模型:为什么32个线程必须执行同一条指令

在AI浪潮席卷全球的今天,GPU已经成为最关键的硬件基础设施。训练一个千亿参数的大语言模型需要数万张GPU协同工作,而每一张GPU内部又同时运行着数百万个线程。这种前所未有的并行能力从何而来?答案藏在GPU最核心的执行模型中——SIMT(Single Instruction Multiple Threads)。 ...

20 min · 10000 words

为什么CPU的字节序至今无法统一:从鸡蛋争议到网络标准

1980年,互联网工程备忘录IEN 137发表了一篇题为《On Holy Wars and a Plea for Peace》的论文。作者Danny Cohen用《格列佛游记》中的鸡蛋争议,比喻计算机界关于字节序的争论。四十多年过去了,这场"圣战"不仅没有结束,反而因为新硬件、新协议的出现变得更加复杂。 ...

14 min · 6657 words

编译器寄存器分配:从图着色到线性扫描的四十年算法博弈

1981年,IBM的研究员Gregory Chaitin面临一个棘手的问题:如何让PL.8编译器生成的代码更高效?当时,程序中的变量远多于处理器寄存器,编译器必须决定哪些变量驻留在寄存器,哪些被"驱逐"到内存。这个看似简单的资源分配问题,实际上是计算机科学中最经典的NP完全问题之一。 ...

10 min · 4809 words
Blog Cover

解析器的代际战争:为什么GCC和Clang都选择了手写解析器

1975年,贝尔实验室的Stephen Johnson做出了一个决定:将C编译器从手写递归下降解析器切换到DeRemer的LALR算法。这是Unix历史上第一次大规模采用自动生成的解析器。然而不到二十年,GCC项目反其道而行之,重新改用手写解析器。Clang紧随其后。直到今天,几乎所有主流编译器——GCC、Clang、V8、Lua——都使用手写递归下降解析器。为什么解析器生成器在工业界遭遇滑铁卢?这场跨越半个世纪的"代际战争"背后,隐藏着怎样的技术权衡? ...

16 min · 7517 words

纠删码如何用50%存储开销实现比三副本更高的可靠性

2012年,微软Azure Storage团队面临一个严峻的选择:存储数据量正以每两天1PB的速度增长,按照传统的三副本策略,这意味着每两天需要采购3PB的存储设备。更糟糕的是,数据中心的电力、制冷和运维成本也随之水涨船高。团队需要一种能在保证数据可靠性的前提下大幅降低存储成本的方案。他们最终选择了纠删码——这项源自1960年代通信领域的技术,在存储系统中找到了新的生命。 ...

10 min · 4931 words

缓存为何总有淘汰的那一刻?从Belady最优到SIEVE的六十年算法博弈

1966年,IBM研究员Laszlo Belady发表了一篇题为《A Study of Replacement Algorithms for a Virtual-Storage Computer》的论文。这篇论文提出了一个看似简单的问题:当缓存空间有限时,应该淘汰哪个数据? ...

15 min · 7063 words