Li Chen 给 Linux 内核提了一个 spawn templates 补丁。

目标很窄:有些工具会反复启动同一个可执行文件,比如频繁调用 Git 的构建工具、开发工具链。既然目标程序一样,能不能把一部分启动信息缓存下来,下次少走几步?

补丁给出的基准提升约 2%。不大,也不能吹成性能革命。

但这事真正有意思的地方,不是 2%。内核讨论很快转向另一个问题:Linux 还要继续围着 fork()+exec() 打补丁,还是该给“创建一个新程序”一条更干净的路?

spawn templates 戳中了痛点,但不是答案

spawn templates 的思路不复杂。

应用先创建一个模板。内核打开目标可执行文件,并缓存一些后续 exec 会用到的信息。真正启动时,再传 argv、envp、文件描述符动作、信号处理等差异化配置。

同一个程序反复上场,别每次都从后台重新登记一次。

问题传统路径spawn templates 想做什么现实限制
典型动作fork()+exec()缓存同一可执行文件的启动信息只适合重复启动同一程序
受益场景构建工具、开发工具链频繁拉起子进程分摊启动准备成本普通应用未必有感
示例反复调用 Git少做部分重复工作不是通用加速器
基准结果正常进程启动路径约 2% 提升不能夸大
合入前景仍是主流路径当前方案基本不会进内核讨论已转向新 API

这里最容易误读的一点是:fork() 不是把父进程的物理内存完整复制一遍。

Linux 有写时复制。很多成本已经被摊薄。

但 fork() 仍然要复制父进程状态、页表和大量上下文。随后 exec() 又把很多刚准备好的东西丢掉。这个路径优雅,但不免费。

Unix 当年这套设计很漂亮:fork() 复制自己,exec() 换上新程序。两个积木拼出复杂行为。

可现代软件把“启动进程”用得太频繁。构建系统、语言运行时、shell、服务管理器、容器工具,都可能把子进程启动当日常消耗。老积木开始硌手。

对工程团队来说,这意味着一件很实际的事:现在不用为了 spawn templates 改代码。它不是一个马上可用的内核能力。

但如果你维护的是构建工具、运行时或大量调用外部命令的系统,应该开始盯住 pidfd 和 posix_spawn() 的后续接口设计。真正可能改变代码路径的,不是这个模板补丁,而是新的进程创建原语。

分歧不在缓存,而在要不要复制父进程

Mateusz Guzik 的批评很直接:fork()+exec() 这个惯用法本身就很糟糕,应该退休。

他的判断点很清楚。spawn templates 只是给 exec 前后的部分流程做缓存,但没有动 fork() 这块主要成本。与其先复制当前进程,再丢掉大部分状态,不如直接创建一个 pristine process,一个干净的新进程。

这才是争论的核心。

路线基本思路好处代价
修补 fork()+exec()继续沿用旧模型,在局部做优化兼容性强,生态扰动小主要低效来源仍在
spawn templates缓存同一可执行文件的部分启动信息对重复启动同一程序有帮助场景窄,收益有限,API 方向被质疑
pidfd 新进程 API先创建空进程,再逐步配置更接近干净的进程创建模型API 设计复杂,合入门槛高
原生 posix_spawn()不再暗藏 fork()+exec()用户态可获得更直接路径需要内核提供合适原语

Christian Brauner 的方向更像内核治理。

他并不反对给 exec 做 builder API,但更倾向把新接口建在 pidfd 上:先通过类似 pidfd_open 的机制创建空进程,再用新的 pidfd_config() 去配置它,包括环境、可执行映像等。这有点像 fsconfig() 管文件系统配置的思路。

重点是支撑用户态真正实现 posix_spawn()。

posix_spawn() 不是新标准,也不是新概念。它本来就适合表达“启动一个新程序”。问题在于,Linux 上很多实现路径仍然会把 fork()/exec() 藏在下面。

开发者想要的不是换个函数名继续走老路,而是一条原生路径。

这会影响谁?不是普通桌面用户先感知。

更相关的是两类人。

一类是运行时、shell、构建工具和语言生态的维护者。他们要判断未来是否能把高频子进程启动切到更直接的 posix_spawn() 路径,而不是继续靠 fork()+exec()。

另一类是容器、服务管理器和系统工具开发者。他们更在意进程能不能被稳定引用、配置和管理。pidfd 路线如果继续推进,进程创建会更像“配置一个对象”,而不是“复制当前进程再改掉它”。

眼下的动作不该是迁移,而是观察接口形态:pidfd_config() 是否成形,能配置哪些状态,是否足以覆盖现有 posix_spawn() 需求,以及 glibc、musl 这类用户态实现会不会跟进。

我更在意 Linux 这次开始认账

spawn templates 本身不是大新闻。

2% 的收益,窄场景,方案还被质疑。它不像一个马上改写 Linux 性能版图的补丁。

但它逼出了一个更诚实的问题:fork()+exec() 的美学红利,还能不能覆盖现代进程启动的成本?

“天下熙熙,皆为利来。”技术世界也一样。

API 能活几十年,不只是因为优雅,也因为迁移成本巨大、生态惯性巨大、没人愿意为破坏兼容背锅。fork()+exec() 是 Unix 传统的一部分,也是无数程序默认假设的一部分。动它,不靠一句“更现代”就能赢。

所以 pidfd 路线看起来更现实。

它不急着废掉 fork()+exec(),而是在旁边长出一条新路:进程先是一个可引用、可配置、可治理的对象,然后再被启动。

这和 Linux 近些年的方向是顺的。pidfd 本来就在补传统 PID 模型的坑。现在如果连进程创建也纳入这套抽象,逻辑并不突兀。

我的判断是:这次少见地问对了问题。

问题不在 spawn templates 这个补丁够不够漂亮,而在 Linux 是否愿意给“启动一个新程序”提供不依赖父进程复制的正经原语。

这也有现实约束。

新 API 不能只为某个基准好看。它必须能覆盖文件描述符动作、信号、环境变量、凭据、命名空间等现实需求。还要让用户态库愿意采用。否则它只是多一个系统调用,多一层维护负担。

fork()+exec() 不会消失,也不该轻易消失。旧制度能活到今天,必有其强处。

但强处不等于永远正确。

这次讨论真正露出来的,是 Unix 传统、性能现实和 Linux API 治理之间的一笔旧账。spawn templates 可能过不了关,账还在。