GIL锁;python垃圾回收机制;计算密集型用多进程,io密集型用多线程

发布时间 2023-08-02 16:22:40作者: 雀雀飞了

GIL锁;python垃圾回收机制;计算密集型用多进程,io密集型用多线程

GIL锁及其作用

1.GIL(Global Interpreter Lock)又称全局解释器锁,本质就是一个互斥锁。
2.它保证了cpython进程中的每个线程必须获得这把锁才能执行,不获得不能执行
3.这样使得在同一进程内任何时刻仅有一个线程在执行。
4.GIL锁只针对于cpython解释器

为什么不用其他python解释器

Jython、Pypy、IronPython没有GIL锁,Pypy速度更快
因为python代码运行在python解释器上,python解释器相当于地基,我们在地基上面盖楼,如果用Pypy的话,有很多模块用不了,Django也无法使用

为什么要有GIL锁

-python是动态强类型语言,因为有垃圾回收机制,如果同一个进程下有多个线程同时在执行,垃圾回收是垃圾回收线程【同一个进程下变量是共享的】,该线程做垃圾回收时,如果其他线程在运行,就可能会出并发安全的问题【数据安全的问题】,由于当时,只有单核cup【即便开启多线程,同一时刻,也只有一个线程在运行】,作者就强行做了一个GIL锁,保证在一个进程内,同一时刻只有一个线程执行,目的是为了防止垃圾回收线程做垃圾回收时,出现数据紊乱问题,所以加了gil锁

-垃圾回收是垃圾回收线程,它在执行的时候,其他线程是不能执行的,而限于当时的条件,只有单核cpu,所以作者直接做了个GIL锁,保证一个进程内同一时刻只有一个线程在执行

python垃圾回收机制

# 什么是垃圾回收
-编程语言在运行过程中会定义变量,也会申请内存空间,后期变量不需要了,该内存空间应该被释放掉
-有些编程语言的这个操作需要程序员自己做(c)
-像java、python、go这些语言都自带GC机制,可以自动回收内存空间
-不同语言的GC方式不一样,python使用如下3种方式,1为主,2、3为辅

1. 引用计数(Reference Counting):
   引用计数是Python垃圾回收的基础机制。当一个对象被创建时,Python会为该对象的引用计数设为1。每当一个变量引用该对象,它的引用计数就会增加1;当变量不再引用该对象(比如变量被删除、重新赋值为其他对象、离开作用域等),对象的引用计数就会减少1。当对象的引用计数减少到0时,说明该对象没有被任何变量引用,即成为垃圾对象,垃圾回收线程会立即释放该对象占用的内存。
'''有问题:循环引用问题回收不了'''

2. 标记清除(Mark and Sweep):
'''解决引用计数无法回收循环引用的问题'''
   当垃圾回收器(garbage collector)被触发时,它会从根对象(通常是全局变量和当前调用栈)出发,遍历所有可访问对象,并对可访问到的对象进行标记。然后,垃圾回收器会清除所有未被标记的对象,这些对象即为不可达的垃圾对象,它们的内存会被释放。
   标记清除的优点是可以解决循环引用的问题,但在进行标记和清除操作时会暂停程序的运行,可能会造成一定的性能损失。

3. 分代回收(Generational Garbage Collection):
'''解决垃圾回收效率问题'''
   它基于这样的观察:大部分对象在内存中存在的时间很短,而只有少数对象会长时间存活。因此,Python将对象按照存活时间划分为不同的代(generation)。一般来说,Python将对象分为三代:0代、1代和2代。新创建的对象属于0代,当0代对象经过垃圾回收后仍然存活,它就会被提升到1代;同理,1代对象经过垃圾回收后仍然存活,就会被提升到2代。Python的垃圾回收器采用不同的频率对不同代的对象进行回收
   分代回收的优点是,它可以根据对象的存活时间来有选择性地进行垃圾回收。通常情况下,大部分垃圾都集中在0代,因此只对0代进行垃圾回收可以更快地完成回收操作,减少全局扫描的开销。减少了全局扫描的开销,提高了垃圾回收的效率

计算密集型用多进程,io密集型用多线程

'''只针对cpython解释器,其他语言都开多线程即可,能够利用多核CPU优势'''
-计算是消耗CPU的:数值计算、图像处理、加密解密都是计算

-io不消耗CPU:文件读写、网络通信、数据库查询等,如果遇到io,该线程会释放CPU的执行权限,CPU转而去执行别的线程

-由于python有GIL锁,开启多线程的话同一时刻只有一条线程在执行

-如果是计算密集型,开了多线程,同一时刻只有一个线程在执行。多核CPU会浪费多核优势,我们希望多个核(cpu),都干活,而同一个进程下绕不过GIL锁。所以我们开启多进程,GIL锁只能锁住某个进程中得线程,开启多个进程,就能利用多核优势
。
-进程内开了多个io线程,线程多半都在等待,开启多进程是不能提高效率的,反而开启进程很耗费资源,所以使用多线程即可