day32-4 GIL全局解释锁

GIL 全局解释器锁

GIL介绍

python程序本质就是一堆字符串,所以运行一个python程序时,必须要开启一个解释器。但是在一个python程序中解释器只有一个,所有代码都要交给它来解释执行,当有多个线程都要执行代码时就会产生线程安全问题。

如python会帮我们进行内存管理,管理也是要写一堆代码,也需要开启一个线程(GC线程)来执行。那就是说就算程序没有自己开启线程,放入解释器执行时也会有多个线程,造成线程安全问题

 

GIL本质就是一把互斥锁,将并发运行变成串行,以此来控制同一时间内共享数据只能被一个任务所修改,进而保证数据安全。所以为解释器加GIL锁,这样在Cpython解释器中,同一个进程下开启的多线程,同一时刻也只能有一个线程执行,无法利用多核优势

 

GIL对多线程的影响与使用

因此只能尽可能避免GIL锁影响程序的效率

1.使用多进程能够实现并行,从而更好的利用多核CPU

2.对任务进行分类

  • 计算密集型:基本上没有IO操作,大部分时间都在计算,例如人脸识别、图像处理。由于多线程不能并行,应该使用多进程将任务分给不同CPU核心
  • IO密集型:计算任务非常少,大部分时间都在等待IO操作。由于网络IO速度对比CPU处理速度非常慢,多线程不会造成太大的影响,另外如有大量客户端连接服务,进程根本开不起来,只能用多线程

 

GIL与自定义锁的区别

GIL锁住的是解释器级别的数据

自定义锁锁的是解释器以外的共享资源,例如:硬盘上的文件应该自己加锁处理

from threading import Thread,Lock
import time

lock = Lock()
a = 0
def task():
    global a
    lock.acquire()
    temp = a
    time.sleep(0.01)
    a = temp + 1
    lock.release()

t1 = Thread(target=task)
t2 = Thread(target=task)
t1.start()
t2.start()
t1.join()
t2.join()
print(a)

过程分析:

1.线程1获得CPU执行权,并获取GIL锁执行代码 ,得到a的值为0后进入睡眠,释放CPU并释放GIL,不释放lock

2.线程2获得CPU执行权,并获取GIL锁,尝试获取lock失败,无法执行,释放CPU并释放GIL

3.线程1睡醒后获得CPU执行权,并获取GIL继续执行代码 ,将temp的值0+1后赋给a,执行完毕释放CPU释放GIL,释放lock,此时a的值为1

4.线程2获得CPU执行权,获取GIL锁,尝试获取lock成功,执行代码,得到a的值为1后进入睡眠,释放CPU并释放GIL,不释放lock

5.线程2睡醒后获得CPU执行权,获取GIL继续执行代码 ,将temp的值1+1后赋给a,执行完毕释放CPU释放GIL,释放lock,此时a的值为2

posted @ 2019-07-07 18:40  Never&say&die  阅读(137)  评论(0编辑  收藏  举报