商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > 为什么Python多线程在CPU密集型脚本中变慢_理解GIL锁与多进程的权衡

为什么Python多线程在CPU密集型脚本中变慢_理解GIL锁与多进程的权衡

  发布于2026-07-08 阅读(0)

扫一扫,手机访问

Python多线程在CPU密集型任务中变慢,这不是写错了代码,而是CPython解释器在背后强制你“排队计算”——GIL让所有线程抢同一把锁,谁拿到谁算,其余只能干等着。这不是bug,而是设计上做的取舍。

为什么Python多线程在CPU密集型脚本中变慢_理解GIL锁与多进程的权衡

原因其实很实在:线程启动、切换、争抢GIL本身就要消耗CPU时间片。而纯计算任务又不触发GIL释放——它不像requests.get()open()那样会主动让出锁——结果多个线程在单核上反复做上下文切换,实际执行仍然是串行的。

为什么threading跑计算任务反而更耗时?

  • 每100个Python字节码指令后,GIL才有可能轮转一次,但轮转开销远大于收益
  • 两个线程做同样总量的计算,耗时通常比单线程多出10%–30%。实测在fibonacci()sum([i**2 for i in range(10**7)])这类场景中经常出现
  • 哪怕用concurrent.futures.ThreadPoolExecutor包装再多层,也绕不开这个底层限制

multiprocessing真能解决问题吗?

能,但代价很明确:进程间不共享内存,每次传参或取结果都要走pickle序列化,数据越大越拖慢速度;启动新进程本身也有毫秒级开销。

  • 适合单次计算量大、参数和返回值都很小的任务(比如对10万行数据做独立数值变换)
  • 避免频繁创建Process——用PoolProcessPoolExecutor复用进程会更划算
  • 注意在Windows下子进程会重新导入模块,必须加上if __name__ == '__main__':,否则会报RuntimeError: An attempt has been made to start a new process

multiprocessing更轻量的替代方案有哪些?

不是所有计算都值得上多进程。先看看能不能“不动线程模型,只换执行体”:

  • NumPy/SciPy数组运算:底层由C/Fortran实现,会自动释放GIL,单线程就能吃满多核
  • concurrent.futures.ProcessPoolExecutor + functools.partial:比裸multiprocessing更容易管理,支持超时和回调
  • Cython或ctypes封装C函数:在C代码段手动调用PyThreadState_ReleasePyThreadState_Swap释放GIL,适合已知的热点函数

真正容易被忽略的点:GIL不是“锁住整个程序”,而是“锁住Python字节码执行”。只要计算逻辑能下沉到不经过解释器的层面(比如向量化、C扩展、甚至subprocess.run(['rust-code'])),就自然绕开了它——优化方向不在于“怎么开更多线程”,而在于“让哪部分代码彻底不走Python解释路径”。

本文转载于:https://www.php.cn/faq/2420644.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注