七、GIL全局解释器锁

GIL全局解释器锁

"""
重点:
	1.GIL不是Python的特点而是CPython解释器的特点
	2.GIL是保证解释器级别的数据的安全
	3.GIL会导致同一个进程下的多个线程的无法同时执行
	4.针对不同的数据还是需要加不同的锁处理
	5.解释型语言的通病:同一个进程下多个线程无法利用多核优势
"""
三个需要注意的点:
#1.线程抢的是GIL锁,GIL锁相当于执行权限,拿到执行权限后才能拿到互斥锁Lock,其他线程也可以抢到GIL,但如果发现Lock仍然没有被释放则阻塞,即便是拿到执行权限GIL也要立刻交出来

#2.join是等待所有,即整体串行,而锁只是锁住修改共享数据的部分,即部分串行,要想保证数据安全的根本原理在于让并发变成串行,join与互斥锁都可以实现,毫无疑问,互斥锁的部分串行效率要更高

一、案例:验证GIL存在

# 验证进程间是相互隔离的
import time
from threading import Thread, Lock

a = 10
mutex = Lock()

def func():
    global a #局部修改全局
    b = a
    a = b - 1
    print(b,end=' ')


if __name__ == '__main__':
    t_list = []
    for i in range(10):
        p = Thread(target=func)
        p.start()
        t_list.append(p)
    for i in t_list:
        i.join()
    print(a)

'''
输出结果:
	10 9 8 7 6 5 4 3 2 1 0

如果GIL不存在,那么我们同时创建多个线程对变量a进行修改,因为不存在锁的约束,最终我们应该都是输出9,输出结果显然不是如此
GIL的存在,是为了保证解释器级别数据的安全,即该进程下的所有线程抢GIL是为了抢解释器的执行权限,此刻所有子线程都没有IO操作,所以抢到了GIL就执行完,从而形成一个完整的串行
'''

二、GIL与Lock的作用不同

'''
首先我们要明白:
	锁的目的是为了保护共享的数据,同一时间只能有一个线程来修改共享的数据

由此得出结论:
	保护不同的数据就应该加不同的锁。
    
因此:
	GIL 与Lock是两把锁,保护的数据不一样,前者是解释器级别的(当然保护的就是解释器级别的数据,比如垃圾回收的数据),后者是保护用户自己开发的应用程序的数据,很明显GIL不负责这件事,只能用户自定义加锁处理,即Lock
	
所有线程抢的是GIL锁,或者说所有线程抢的是执行权限
在抢到GIL锁后,还需要抢Lock锁,从而保证线程间数据的同步

案例:GIL与Lock

# 验证进程间是相互隔离的
import time
from threading import Thread, Lock

a = 10
mutex = Lock()


def func():
    global a #局部修改全局
    mutex.acquire()
    b = a
    time.sleep(0.1)
    a = b - 1
    mutex.release()
    print(b,end=' ')


if __name__ == '__main__':
    t_list = []
    for i in range(10):
        p = Thread(target=func)
        p.start()
        t_list.append(p)
    for i in t_list:
        i.join()
    print(a)

'''
输出结果:
	10 9 8 7 6 5 4 3 2 1 0

如果不加入Lock锁,那么在time.sleep(0.1)的时候,线程就会将GIL释放,以此类推,所有线程都会得到b=a=10的值,从而进行a=b-1的操作时,得到的值都只会是9,数据的同步就出现的问题
'''

1、GIL与Lock综合分析

分析:
  #1.100个线程去抢GIL锁,即抢执行权限
     #2. 肯定有一个线程先抢到GIL(暂且称为线程1),然后开始执行,一旦执行就会拿到lock.acquire()
     #3. 极有可能线程1还未运行完毕,就有另外一个线程2抢到GIL,然后开始运行,但线程2发现互斥锁lock还未被线程1释放,于是阻塞,被迫交出执行权限,即释放GIL
    #4.直到线程1重新抢到GIL,开始从上次暂停的位置继续执行,直到正常释放互斥锁lock,然后其他的线程再重复2 3 4的过程

2、互斥锁与join的区别

'''
需知join是等待子线程所有的代码执行完,相当于锁住了子线程的所有代码,而Lock只是锁住一部分操作共享数据的代码。

Lock是比join效率更高的方法
posted @ 2021-06-03 21:34  zzwYYYYYY  阅读(47)  评论(0)    收藏  举报