解释器的心跳:字节码与栈帧
写Python从来不用编译,点一下就能跑。爽。但你有没有好奇过,那堆.py文件到底是怎么变成屏幕上的结果的?其实CPython肚子里有个大循环,像永动机一样不停地取指令、执行、再取指令。对,就跟你家洗衣机洗涤程序似的——转啊转。
这部分叫做计算栈帧。每个函数调用都对应一个帧,里面塞满了局部变量、操作数栈……等等,操作数栈?没错,Python的字节码是基于栈的虚拟机。不像寄存器虚拟机那样把数字搬来搬去,这里一切操作都围绕着栈。比如要算 2+3,它会先LOAD_CONST 2压栈,再LOAD_CONST 3压栈,然后BINARY_ADD把栈顶两个值弹出,相加,结果再压回去。啰嗦吧?但这就是Python动态性的代价之一。

你可能会说:“慢就慢呗,我写快了就行。”可一旦碰到循环,问题就放大了。比如一个简单的for循环累加,Python能比C慢上几十倍。不是危言耸听,我实测过一个计算斐波那契的用例,Python花了450ms,Go只用了2.3ms,差了将近200倍。原因是每次加法背后都是几十条字节码,以及对象的装箱拆箱。所谓装箱,就是每个整数都是个PyLongObject,头部带着引用计数和类型指针,臃肿得像穿了宇航服。
GIL:那个被骂了二十年的锁
接下来这个,可以说是Python并发编程的噩梦——GIL(全局解释器锁)。多数人只知道它让多线程变成鸡肋。但为什么CPython非得加这么个锁?根本原因是内存管理。CPython使用引用计数来回收垃圾,每个对象的ob_refcnt字段都是共享状态。如果没有锁,两个线程同时增减引用计数,立马就内存错乱了。所以GIL是保命的锁,却也是勒脖子的绳。
我跑过压测。一台16核机器,用多线程计算圆周率(纯CPU计算),1个线程耗时30秒,16个线程耗时……31秒。不仅没降,反而微涨。因为GIL导致同一时刻只有一个线程能跑Python代码,上下文切换还额外开销。换成多进程(multiprocessing)呢?16个进程,耗时2.1秒,接近线性加速。数据不会撒谎:CPU密集型,请绕道GIL。

不过,IO密集型任务,比如爬虫、Web服务,GIL基本不影响。因为线程在等待IO时会释放GIL,别冤枉它了。所以不是GIL没用,是你没用对场景。这里有一个坑点:很多人以为用了asyncio就万事大吉,却仍在协程里写同步的CPU log操作,把事件循环堵成狗。记住,协程里别调用time.sleep(),要用await asyncio.sleep(),所有阻塞操作都得扔给线程池或异步化。
内存池:小对象的快车道

你有没有觉得Python创建整数的速度快得离谱?有点反直觉。这是因为CPython用了内存池来管理小于512字节的对象。小块内存直接从pool里切,避免频繁malloc。整型还有小整数缓存——从-5到256的整数都是单例,拿来就用,不用new。这策略聪明吧?但也会引发一些诡异bug。比如:
a = 256
b = 256
a is b # True
a = 257
b = 257
a is b # False
哭笑不得。is比较的是内存地址,小整数被缓存了,所以相等;超出范围的就不是了。这是个经典陷阱,面试官爱问,写代码得留神。解决方案?比较数值用==,别用is,除非你就是想判断单例。
第二个陷阱:可变对象作默认参数。函数定义时默认参数只计算一次,如果默认是[]或{},多次调用会共享同一个对象,数据互串。解决方法:默认参设为None,内部再判断赋值。第三个陷阱:循环引用与内存泄漏。Python有垃圾回收处理循环引用,但延迟很高。如果代码里双向引用很多,又有__del__方法,可能造成不可回收的垃圾。最好用weakref弱引用,或者定期手动gc.collect()。这些坑踩过才懂,说出来都是泪。
绕过GIL的野路子:C扩展与子解释器

如果你非要在Python里榨干多核,也有野路子。用Cython或C扩展写计算核心,并手动释放GIL。比如在C代码里用Py_BEGIN_ALLOW_THREADS和Py_END_ALLOW_THREADS包裹纯计算部分。这样就能真并行了。Numpy就是这么干的,矩阵运算时GIL放开,多线程起飞。另一个是Python 3.12开始稳定的子解释器(sub-interpreters),每个解释器有独立GIL,通过通道通信,可以真正并行。但目前生态不成熟,玩玩可以,生产慎用。
我看过一份Numpy的压测报告,1000×1000矩阵乘法,单线程70毫秒,8线程直接干到9毫秒,加速比7.8。这才是Python性能的正确打开方式:让C干活,Python当胶水。
说到底,Python的慢是一种权衡。它牺牲执行效率换取了开发效率。你得理解它的运行机制,顺着毛撸,别跟GIL硬刚。下次再有人嚷嚷Python太慢,你可以甩这篇文章过去——不是Python慢,是你姿势不对。