Python GIL全局解释器锁

GIL解释:

GIL:Global Interpreter Lock 全局解释器锁,设计目的是保证数据安全。

GIL 的功能是:在 CPython 解释器中执行的每一个 Python 线程,都会先锁住自己,以阻止别的线程执行。也就是说在解释器执行任何Python代码时,都需要先获取这把锁,意味着任何时候只可能有一个线程在执行代码,其他线程要想获得CPU去执行代码,就必须等到占有该锁的线程释放锁才有执行的可能。

当然Python中不会让一个线程一直独占解释器,它会轮流执行 Python 线程,即 Python 线程在交替执行,来模拟真正并行的线程(伪并行),但Python中每次释放GIL锁,线程进行锁竞争、切换线程,都会造成资源消耗,并且由于GIL锁存在,python里一个进程永远只能同时执行一个线程(拿到GIL的线程才能执行),导致在多核CPU上,Python的多线程效率并不高。

如果所示,三个线程交替执行,借此模拟并行。但某一时刻,程序中只有一个线程在执行,其他线程在等待其释放锁。

GIL 的特点:

1. Python在多线程下,每个线程的执行方式为:

  • 获取GIL
  • 执行代码直到sleep或者是python虚拟机将其挂起。
  • 释放GIL 

2. 一个CPU只能执行一个线程 ,例如一个CPU 有三个线程 ,首先线程A执行 ,然后
线程A达到释放条件进行释放GIL,线程B 和线程C 进行竞争GIL ,谁抢到GIL ,继续执行.

3. 一个进程里有多线程,但只有一个GIL 锁,不同的进程GIL 锁互不干扰,

4. 单个CPU多线程比多核多线程更快解释如下:

(单核内线程之间切换可以几乎达到无缝连接,但是在多核情况下一个线程 A释放GIL 锁,其他CPU上的线程都会进行竞争,但是有可能线程A 又抢到这个锁,导致其他几个CPU上被唤醒后的线程会醒着等待到切换时间后又进入待调度状态,
这样会造成线程颠簸(thrashing),导致效率更低.

5. 多核CPU和C 语言相比,python的多线程效率并不高.解释如下:

  • 释放GIL,和切换线程 需要消耗资源
  • 一个进程只能运行一个线程 (拿到GIL的线程才能执行),即使是多核CPU,也没办法让多个线程并行执行代码,只能是交替执行。

GIL释放

  1. 当一个线程遇到 I/O 任务时,将释放GIL,避免输入I/O操作浪费时间。这个特性是优于其他语言的。
  2. 计算密集型(CPU-bound)线程执行 100 次解释器的计步(ticks)时(计步可粗略看作 Python 虚拟机的指令),步数/时间到达阈值也会释放 GIL。但是效率依然不尽人意。

解决:

Python下想要充分利用多核CPU,采用多进程并发编程。这是因为多核下每个进程有各自独立的GIL,互不干扰,实现真正意义上的并行。

垃圾回收机制简述:

1. Python中垃圾回收引用了计数机制,对象每引用一次即在计数器中加一,当一个对象在计数器中的计数为0时,说明这个对象不再使用,自然它就变成了垃圾,需要被垃圾回收器回收。

2. 可能存在循环引用(只有容器类对象才有可能产生循环引用)的对象,但它们不再使用,Python中使用标记清除(mark-sweep)算法和分代收集(generational),来启动针对循环引用的自动垃圾回收。

标记算法:用图论来理解不可达的概念。对于一个有向图,如果从一个节点出发进行遍历,并标记其经过的所有节点;那么,在遍历结束后,所有没有被标记的节点,我们就称之为不可达节点。显而易见,这些节点的存在是没有任何意义的,自然的,我们就需要对它们进行垃圾回收。

分代收集算法:将 Python 中的所有对象分为三代。刚刚创立的对象是第 0 代;经过一次垃圾回收后,依然存在的对象,便会依次从上一代挪到下一代。而每一代启动自动垃圾回收的阈值,则是可以单独指定的。当垃圾回收器中新增对象减去删除对象达到相应的阈值时,就会对这一代对象启动垃圾回收。(新生的对象更有可能被垃圾回收,而存活更久的对象也有更高的概率继续存活

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值