Python GIL 与并发模型选型:多线程、多进程还是协程

举报
yd_268144123 发表于 2026/11/14 09:48:42 2026/11/14
【摘要】 一、GIL 是什么GIL(Global Interpreter Lock,全局解释器锁) 是 CPython 解释器里的一把互斥锁:同一时刻,一个 Python 进程内只有一个线程能执行 Python 字节码。很多人的第一反应是“那多线程不就没用了?”——并不完全对。要理解 GIL 的影响,得先分清任务类型:CPU 密集型 和 I/O 密集型。 二、GIL 为什么存在CPython 用引用...

一、GIL 是什么

GIL(Global Interpreter Lock,全局解释器锁) 是 CPython 解释器里的一把互斥锁:同一时刻,一个 Python 进程内只有一个线程能执行 Python 字节码。

很多人的第一反应是“那多线程不就没用了?”——并不完全对。要理解 GIL 的影响,得先分清任务类型:CPU 密集型 和 I/O 密集型。

二、GIL 为什么存在

CPython 用引用计数做内存管理,多线程同时改引用计数会出错,加锁是最简单的解法;同时 GIL 让单线程执行变快、C 扩展编写更简单。这是权衡的结果,不是“设计缺陷”。

代价就是:多线程无法真正并行跑 Python 字节码。

三、GIL 对两类任务的影响

CPU 密集型(计算、加密、图像处理……)

线程大部分时间在算,而 GIL 让它们只能轮流跑,多线程甚至因为切换开销比单线程还慢。多线程在此无收益。

I/O 密集型(网络请求、读写文件、数据库访问……)

线程在等待 I/O 时会主动释放 GIL,此时别的线程可以继续跑。所以多线程对 I/O 密集任务是有效的——等待时间被重叠了。

四、三种并发模型怎么选

模型 适用场景 关键点
多线程 threading I/O 密集型 轻量、共享内存;受 GIL 限制不能并行计算
多进程 multiprocessing CPU 密集型 每进程独立解释器和 GIL,真正并行;进程间通信/内存开销大
协程 asyncio 高并发 I/O 单线程事件循环,切换开销极小;适合海量连接

选择口诀:计算密集用多进程,I/O 密集用多线程或协程,海量并发连接优先协程。

五、代码对比

CPU 密集:多进程更快

from multiprocessing import Pool

def heavy(n):
    return sum(i * i for i in range(n))

if __name__ == "__main__":
    with Pool(4) as p:                 # 4 个进程,真并行
        print(p.map(heavy, [10**7] * 4))

用 threading 跑同样的计算基本不会加速,因为 GIL 让它们串行。

I/O 密集:协程最省资源

import asyncio, aiohttp

async def fetch(session, url):
    async with session.get(url) as resp:
        return await resp.text()

async def main(urls):
    async with aiohttp.ClientSession() as s:
        return await asyncio.gather(*(fetch(s, u) for u in urls))

urls = ["https://example.com"] * 100
asyncio.run(main(urls))   # 100 个请求并发,单线程即可

协程在 I/O 等待时让出控制权,用极小的开销实现高并发。

六、绕过 GIL 的几种方式

  1. 多进程:最直接,进程级隔离,各有一把 GIL。
  2. C 扩展 / 原生库:NumPy、pandas 等底层是 C,计算时释放 GIL,能真正并行。
  3. 用别的解释器:Jython、IronPython 无 GIL;PyPy 有 STM 实验;CPython 3.13 起有实验性 free-threaded(无 GIL)构建,但生态尚在完善。
  4. 把重活丢给外部服务:如交给 C/Rust 服务、数据库、GPU 计算。

七、常见误区

  1. “Python 多线程完全没用”:错。I/O 密集型多线程依然有效。
  2. CPU 密集用多线程想加速:往往白忙,应换多进程。
  3. 协程里写阻塞调用:在 async 函数里调用同步 requests/time.sleep 会卡死整个事件循环,要用异步库或 run_in_executor。
  4. 多进程共享大对象:序列化/拷贝开销可能吃掉并行收益,注意数据传递成本。
  5. 线程数开太多:上下文切换和内存开销反噬性能,按 CPU 核数和任务类型合理设。

八、总结

GIL 决定了 CPython 单进程内多线程无法并行执行字节码,因此:

  • CPU 密集型 → 多进程(或多用 C 扩展);
  • I/O 密集型 → 多线程 / 协程;
  • 海量并发 I/O → 协程(asyncio)。

理解任务类型是选对并发模型的前提。GIL 不是“Python 慢”的借口,选对模型、把重活交给能释放 GIL 的原生库,Python 一样能跑得又快又稳。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。