Python 并发编程(二) GIL (全局解释器锁)

Python 全局解释器锁 GIL (Global Interpreter Lock),简单来说是一个互斥锁,它同一时间只允许一个线程控制 Python 解释器。

这意味着在任何时间点都只能有一个线程处于执行状态。由于即使在具有多个 CPU 内核的多线程架构中,GIL 也只允许一次执行一个线程,因此 GIL 被称为 Python 最“臭名昭著”的特性。

1. 为什么需要GIL

Python 使用引用计数进行内存管理(参考Python中的内存管理)。这意味着在 Python 中创建的对象有一个引用计数变量,用于跟踪指向该对象的引用数量。当这个计数降为0时,对象占用的内存被释放。

引用计数变量需要避免被两个线程同时增加或减少其值, 否则可能会造成错误的引用计数值, 使得对象被误删除或者永不删除内存泄漏.

这个引用计数变量可以通过向所有线程共享的数据结构添加来保持安全,这样它们就不会被不一致地修改。但是为每个对象或对象组添加锁意味着将存在多个锁,这可能会导致

  • 死锁
  • 性能下降 (重复获取和释放锁导致)

GIL 是解释器本身的单锁,它的规则是,即执行任何 Python 字节码都需要获取解释器锁。这可以防止死锁(因为只有一个锁)并且不会引入太多的性能开销。但它的副作用是使 Python 程序成为单线程程的。

2. GIL 对多线程程序的影响

2.1 CPU密集型 vs IO密集型

任何计算机程序, 我们可以把任务分为计算密集型和IO密集型。

CPU 密集型程序是那些将 CPU 推到极限的程序。这包括进行矩阵乘法、搜索、图像处理等数学计算的程序。

I/O 密集型程序是花费时间等待输入/输出的程序, 可以来自用户,文件,数据库,网络等.这类任务的特点是CPU消耗很少,任务的大部分时间都在等待IO操作完成(因为IO的速度远远低于CPU和内存的速度)

2.2 GIL 对 CPU密集型程序的影响

创建一个简单的cpu密集型程序, 计算1亿内数据的和, 单进程和多进程版本代码如下

 运行2个文件, 得到如下输出:

$ python single_thread.py
Time elapsed:  5.9450558000000004

$ python multi_thread.py
Time elapsed:  5.978349

从结果可见, 两个版本几乎都需要相同的时间来完成。因为在多线程版本中,GIL 阻止了CPU密集型线程并行执行。多线程版本甚至增加了执行时间, 是因为增加了锁的获取和释放的开销的结果。

 2.2 GIL 对 I/O密集型程序的影响

创建一个简单的I/O密集型程序, 发送20个http请求,单进程和多进程版本代码如下。

可以看到,多线程版本性能提高了将近1倍, GIL 对 I/O 绑定多线程程序的性能没有太大影响,因为在等待 I/O 的线程之间共享锁。

$ python single_thread_io.py
Time elapsed:  13.6694124

$ python multi_thread_io.py
Time elapsed:  7.2252728

3. 如何应对GIL带来的问题

3.1 使用多进程

对于cpu密集型程序, 选择使用多个进程而不是线程。每个 Python 进程都有自己的 Python 解释器,内存空间和自己的GIL。 使用multiprocessing 模块的代码样例

 分别运行两个文件, 对比执行的时间, 可以看到多进程的版本性能有不小的提升。

$ python single_process.py
Time elapsed:  6.5235679

$ python multi_process.py
Time elapsed:  3.9338849999999996

但是运行2个进程, 时间并没有减少到一半,因为流程管理有它自己的开销。

需要注意的是, 多进程比多线程更重。

3.2 使用其他解释器

因为 GIL 仅存在于 Python 的原始实现 CPython 中, 如果实在讨厌 GIL 可以选择其他的解释器实现。如 Jython、IronPython 和 PyPy

总结:

GIL 是一个互斥锁,执行任何 Python 字节码都需要获取解释器锁。

由于 GIL 的存在, Python中的多线程为伪多线程, 因为同一时间只允许一个线程控制 Python 解释器。

对于I/O密集型程序, 使用多线程。

对于cpu密集型程序, 使用多进程。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值