压测一跑,CPU 100%,机器风扇跟要起飞一样,代码一行没改,吞吐却能从每秒几百条蹿到几万。第一次看到这组数据,我第一反应不是“Python 变快了”,而是这里八成有人把账算错了。

后来翻 perf、看火焰图、再把启动命令扒开,才发现慢的根本不是业务逻辑本身,是解释器在硬扛。很多 Python 服务慢,不是慢在你那几行 if else,也不是慢在 for 循环写得土,慢在默认跑法太老实。默认解释器能跑,但不一定适合线上吞吞吐吐的活。

比如下面这段代码,逻辑很普通,做日志清洗、字段归一化,再聚合统计。很多内部脚本、数据处理接口,本质上都长这样:

import json
from collections import defaultdict

def handle(lines):
    counter = defaultdict(int)

    for raw in lines:
        item = json.loads(raw)
        uid = item.get("user_id")
        event = item.get("event")
        if not uid or not event:
            continue

        key = f"{uid}:{event}"
        counter[key] += 1

    return counter

这段代码改不改,当然还能继续抠。比如少建点对象,少拼点字符串,换个更快的 json 库。但有些场景里,你还没开始改业务,先把运行时换掉,收益就已经很离谱了。

我这边更常见的一套做法,是直接把 CPython 换成 PyPy 跑一轮基准。尤其是这种长时间运行、纯 Python 逻辑占比高、对象创建频繁的任务,效果经常比改几天代码还直接。

命令不用花活:

pypy3 worker.py

或者你原来是这么起:

python3 app.py

现在改成:

pypy3 app.py

就这一刀。

为什么会这样?因为 PyPy 不是单纯换个壳,它有 JIT,会把热点代码在运行时编译优化。那种反复执行的 Python 路径,CPython 是老老实实一句句解释,PyPy 会盯住热点循环狠狠干。请求一多、任务一长,差距就出来了。

我之前拿一个内部清洗脚本做过对比,逻辑和上面差不多,输入是几百万行 JSON 日志。CPython 跑完要几十秒,PyPy 下去直接压到 1 秒级,倍数看着夸张,但真不是玄学。你要是业务里正好堆着大量字符串处理、字典操作、循环判断,这种收益并不稀奇。

简单压测脚本也能自己跑:

import time
import json

payload = json.dumps({
    "user_id"1024,
    "event""pay",
    "amount"99,
    "ts"1710000000
})

def work(n=2_000_000):
    hit = 0
    for _ in range(n):
        obj = json.loads(payload)
        if obj["amount"] > 10:
            hit += 1
    return hit

start = time.time()
total = work()
print(total, round(time.time() - start, 3))

同一台机器,别先看“理论上”,直接分别用 python3 和 pypy3 跑,结果通常很诚实。

不过这事也不是见谁都上。第一眼我一般先看三个东西。

先看热点是不是在 Python 层。要是你服务 80% 时间都耗在 MySQL、Redis、HTTP 调用上,那你换解释器,收益很有限,瓶颈根本不在本地执行。

再看有没有 C 扩展重依赖。像 numpy、pandas 这类库,很多场景本来就跑在底层 C 上,PyPy 不一定占便宜,有些包兼容性还得单独验证。

最后看任务是不是“热得起来”。PyPy 的 JIT 需要预热,短命脚本、跑一下就退出的命令行工具,未必划算。常驻进程、批处理任务、消费程序,这种更适合。

线上判断也不复杂,别一上来全量切。先拿一个 CPU 高、外部依赖少的 worker 灰度。盯三组指标就够了:单机吞吐、CPU 使用率、P99 延迟。数据好看再放量,数据不好立刻回切,成本其实不高。

还有个细节很多人会漏:别拿“冷启动第一分钟”的数据下结论。PyPy 预热前没那么猛,你要看稳定运行后的曲线。这个跟 JVM 有点像,别刚起服务就拍桌子说没提升,那多半是看早了。

所以这事真正有意思的地方,不是 Python 忽然变神了,而是很多人默认把“性能优化”等同于“改代码”。其实有时候不用碰业务逻辑,先把运行时、启动方式、执行环境这几件事看一遍,收益可能更大。

代码当然还能继续抠,但在动刀之前,我更愿意先确认一件事:你现在这份代码,到底是写得慢,还是跑得冤。