大部分人做语言,目标是更快。 这门语言的目标是更慢,而且慢得可测量、可复现、 写进 ADR。

指标是:比 CPython 慢至少两个数量级,也就是 ≥100 倍。

两个基线,都报

「比 CPython 慢多少倍」这句话本身是不完整的——你得先说清 算的是哪一段。所以我用两个口径分别测:

基线口径CPython倍数达标
A 只算执行(timeit,code object 预编译) 0.37 微秒/次 686 倍(2.84 个数量级) ✅
B 全流程(exec,含编译) 24.4 微秒/次 12.1 倍(1.08 个数量级) ❌

pyPython 自身约 255 微秒/次。

注意最后那一列。基线 B 没达标——12.1 倍, 离 100 倍差得远。

这张图我也把「未达标」标了出来:

性能对比图:pyPython 与两个基线的耗时范围

为什么不把没达标那条藏起来

因为那是测量,不是宣传。

ADR-0001 里写了一条原则:测量不打算造假。 如果只报基线 A,结论会好听得多——「慢 686 倍,超额完成」。 但基线 B 才是用户真正感知到的速度:他敲一行代码、按回车、 等结果。那一段包含了编译,而编译是慢的大头。

只报 A 等于告诉用户一个他自己测不出来的数字。

为什么画「范围」而不是一根柱子

这是做图时最花时间的一个决定。我先采样了 14 轮,结果很说明问题:

被测对象范围离散度
pyPython 自身244 ~ 279 微秒14%(稳)
基线 A(timeit)0.368 ~ 0.85 微秒120%(很不稳)
基线 B(exec)20 ~ 35 微秒59%(不稳)

基线 A 抖了 120%。原因很简单:它本身只有零点几微秒, GC 一次、系统调度一次,分母就能翻倍。

这种情况下画「一根精确的柱子」是撒谎。所以图上画的是 中位数 + 实测范围,并且在图里直接写明采样轮数和 「次之间会有偏差」。

结论是稳的

虽然具体倍数在漂,但量级结论不漂:

  • 基线 A:462 ~ 743 倍 —— 永远 ≥2 个数量级 ✅
  • 基线 B:6.9 ~ 12.9 倍 —— 永远 <2 个数量级 ❌

所以「慢两个数量级」这个说法,在基线 A 的口径下成立, 在基线 B 的口径下不成立。这两句话我都要说。

那它靠什么慢下来的

不是靠「写得烂」。是靠每一步都绕一圈:

  • 值不直接存,走一套自定义的 encode/decode (长度前缀编码,见 ADR-0003)
  • 任何值判断真假都要过一遍「真值密室」
  • AST 每个节点单独走一遍求值

这些在正常语言里都是要被优化掉的。这里是特意保留的—— ADR-0002 写着:语法越简单,实现越应当啰嗦。

一门语言把语法减到极致,通常是为了让实现也简单。 这里反过来了:语法减到极致,实现却要故意绕远路。