Python多线程居然比单线程还慢?是哪里出问题了

简介: 本文揭秘Python性能“玄学”:为何双线程计算反比单线程慢2倍?根源在于GIL(全局解释器锁)——它强制同一时刻仅一个线程执行字节码,使CPU密集型任务无法并行。文章详解GIL成因、代价,并给出三大破解方案:多进程、C扩展库(如NumPy)、asyncio;最后展望无GIL的Python 3.14新特性。(239字)

免费编程软件「python+pycharm」

链接:https://pan.quark.cn/s/48a86be2fdc0

一个让我怀疑人生的性能测试

去年有个朋友跑来找我,说他写了个多线程程序,结果慢得离谱。原代码长这样:

import threading
import time

def compute():
   total = 0
   for i in range(100_000_000):
       total += i
   return total

# 单线程
start = time.time()
compute()
print(f"单线程耗时: {time.time() - start:.2f}秒")

# 两个线程并行
threads = []
start = time.time()
for _ in range(2):
   t = threading.Thread(target=compute)
   threads.append(t)
   t.start()
for t in threads:
   t.join()
print(f"双线程耗时: {time.time() - start:.2f}秒")

他跑出来的结果:

单线程耗时: 3.8秒
双线程耗时: 8.2秒

他盯着屏幕看了五分钟,冒出一句:"为什么两个线程反而比一个线程慢了一倍多? 是我写错了吗?"

代码没错,他遇到的是Python最著名、最坑人的那个"特性"——GIL(全局解释器锁)

今天我就把GIL这件事彻底讲清楚,包括它为什么存在、它怎么坑人、以及你该怎么绕开它。

代理 IP 使用小技巧 让你的数据抓取效率翻倍 (36).png


GIL到底是什么?

GIL的全称是Global Interpreter Lock,中文叫"全局解释器锁"。它是CPython(就是最常用的那个Python实现)里的一个互斥锁

它干了一件事:保证同一时刻,只有一个线程能执行Python字节码

你可以把它想象成游乐场里最热门项目的"排队手环"——谁拿到手环,谁才能玩。玩一会儿(大约15毫秒,或者执行固定数量的字节码指令),就得把手环交出来,让下一个人玩。

这个设计让CPython的内存管理变得简单安全。Python用引用计数来管理内存,每个对象都记录自己被引用了多少次。如果没有GIL,多个线程同时修改一个对象的引用计数,会造成数据错乱,导致内存泄漏或程序崩溃。

GIL的代价:在多核CPU上,你开的多个Python线程无法真正并行执行计算任务。它们只是在同一个核上轮流跑,而且因为频繁切换,还产生了额外的开销。


为什么计算密集型任务,多线程反而更慢?

当一个计算密集型任务(比如上面那个大循环)在多线程下运行时,CPU实际上在反复做这几件事:

  1. 线程A拿到GIL,执行计算(约15毫秒)
  2. 线程A释放GIL,进入等待状态
  3. 操作系统调度线程B获得CPU
  4. 线程B获取GIL,开始执行计算
  5. 线程B释放GIL,进入等待状态
  6. 操作系统调度线程A获得CPU
  7. 线程A获取GIL,继续执行计算
  8. 循环往复……

本来一个线程可以连续计算3.8秒完成的任务,现在变成了两个线程反复争夺GIL和CPU。每次切换都有开销(保存上下文、恢复上下文、锁竞争),这些开销加起来,反而让总耗时增加了。

关键点:多线程并没有"并行"执行,只是在"并发"地抢GIL。对于纯计算任务,线程数越多,上下文切换越频繁,效率越低。


那多线程在Python里还有什么用?

有用。I/O密集型任务

比如网络爬虫、文件读写、数据库查询——这些任务大部分时间在等待外部资源(网络响应、磁盘读写)。当一个线程在等待I/O时,它会主动释放GIL,让其他线程有机会执行。

所以,对于I/O密集型任务,Python多线程确实能提速——你可以在等待一个请求返回的同时,发出另一个请求。

I/O密集型场景示例:
- 爬虫同时请求10个网页
- Web服务器同时处理多个用户请求
- 批量读写多个文件


破解GIL的三大方案

方案1:多进程(multiprocessing)

既然GIL只限制线程,那就用进程。每个进程有自己独立的GIL,可以真正并行。

from multiprocessing import Pool

def compute():
   total = 0
   for i in range(100_000_000):
       total += i
   return total

with Pool(4) as pool:
   results = pool.map(compute, range(4))

测试结果:4个进程并行,耗时降到约1.1秒,加速比接近4倍。

代价:进程间通信成本高,数据共享需要用队列或共享内存,代码复杂度增加。

方案2:用C扩展库

NumPy、Pandas这些库底层是C语言写的,执行计算时会释放GIL,所以多线程依然能加速。

这就是为什么数据科学领域用Python做大量矩阵运算依然很快——真正吃性能的部分是C写的。

方案3:异步编程(asyncio)

对于I/O密集型任务,asyncio可以在单线程内高并发地处理大量I/O,效率高于多线程。


好消息:无GIL的Python正在到来

Python 3.13已经提供了实验性的无GIL构建版本(自由线程,Free-Threaded)。Python 3.14进一步改进了这个特性,让它在性能和稳定性上更接近生产可用。

测试表明,对于可并行、数据独立的工作负载,无GIL版本能把执行时间缩短到原来的1/4,能耗也大幅下降。

但需要注意:

  • 单线程性能会略有下降(约5-10%)
  • 内存占用会增加(约10%,因为引入了更细粒度的锁)
  • 第三方库的兼容性还在逐步完善

结论:判断任务类型,选择合适的工具

回到开头的问题:为什么你的多线程比单线程慢?

因为你的任务是CPU密集型的,而GIL让多线程无法真正并行。

记住这张表:

任务类型 推荐方案 原因
CPU密集型(计算、循环) 多进程或C扩展 绕开GIL
I/O密集型(网络、文件) 多线程或asyncio I/O等待时释放GIL
简单I/O并发 asyncio 更轻量,无GIL限制

你那个"双线程比单线程慢一倍"的现象,就是因为两个线程在抢GIL,切换开销大于计算收益。

解决方案:用multiprocessing,或者把计算逻辑改成numpy实现。下次别再被GIL坑了。

目录
相关文章
|
5天前
|
人工智能 自然语言处理 数据可视化
阿里云万小智收费价格:AI建站15元1个月、180元一年,免费送CN域名
阿里云万小智AI建站,轻量版仅15元/月(180元/年),免费送.CN域名及2000灵感值;支持内地(需备案)与香港(免备案)双节点部署。含服务器、存储、CDN等全栈资源,对话式建站,10分钟上线。阿里云万小智官网:https://t.aliyun.com/U/FmBHHe
65 2
|
7天前
|
人工智能 安全 Cloud Native
Higress 新发布:AI Gateway 能力增强,Gateway API 及其推理扩展持续打磨
增强 AI 网关能力,持续打磨 Gateway API 及其推理扩展。
360 126
|
27天前
|
人工智能
阿里云ai模型预付费资源包:全模型通用抵扣支持百炼150多款模型,低至4.5折
阿里云百炼AI通用节省计划,预付费享4.5–5折优惠,支持150+款阿里直供模型(含Qwen、万相、语音等),覆盖推理、工具调用等费用。包月5折、包季4.5折,最低10元起,自动抵扣、即买即用。阿里云官方活动链接:https://t.aliyun.com/U/OTnSAH
226 0
|
2月前
|
运维 Shell 网络安全
OpenClaw 微信通道部署指南 私域运营与自动化客服落地方案
OpenClaw是轻量级开源框架,专为企业微信私域运营与自动化客服设计。支持本地、云端、命令行三模式一键部署,兼容多环境,降低接入门槛;内置安全通信、长连接保活与故障自愈能力,开箱即用,助力中小企业快速落地私域运营。(239字)
|
3月前
|
自然语言处理 并行计算 计算机视觉
MoE技术分享
MoE(Mixture of Experts,混合专家模型)的概念最早可以追溯到 1991 年的相关论文。这一开创性工作为后续 MoE 模型的发展奠定了理论基础,其核心思想是采用“分而治之”的方式,将复杂任务拆解为多个子问题,并分别交由不同的“专家”模型处理,从而提升模型的表达能力和处理效率。
|
4月前
|
运维 安全 API
网络安防实战:如何用IP查询工具精准定位风险IP?
本文基于对200+真实攻击案例的分析,总结出风险IP的5种典型特征,并提出一套基于IP查询工具的自动化识别方案。实测数据显示,该方案可将告警误报率降低40%以上,将单次IP研判时间从分钟级压缩到秒级。
|
11月前
|
存储 算法 Sentinel
熔断降级
本内容介绍了微服务中熔断降级的实现原理及Sentinel的底层机制。通过OpenFeign集成Sentinel,利用断路器统计异常和慢请求比例,触发熔断并降级,提升系统稳定性。还讲解了Sentinel使用的限流算法,如滑动窗口、令牌桶和漏桶算法,以应对不同场景下的流量控制需求。
|
11月前
|
数据采集 监控 Java
Python 函数式编程的执行效率:实际应用中的权衡
Python 函数式编程的执行效率:实际应用中的权衡
423 102
|
8月前
|
运维 安全 应用服务中间件
强化网站安全的利器(Nginx中如何正确配置HSTS安全头)
本文介绍如何在Nginx中配置HSTS安全头,提升网站安全性。通过启用HSTS,强制浏览器使用HTTPS通信,有效防御中间人攻击。内容涵盖配置步骤、参数详解、注意事项及验证方法,适合新手快速上手,助力实现Web安全最佳实践。
|
人工智能 云计算 数据中心
加码香港!连续市场第一,启动新计划
加码香港!连续市场第一,启动新计划
644 4