一. 什么是GIL全局解释器锁
GIL 本质就是一把互斥锁,相当于执行权限,每个进程内都会存在一把GIL锁,同一进程内的多个线程必须抢到GIL之后才能使用CPython解释器来执行自己的代码,即同一进程下的多个线程无法实现并行但是可以实现并发
在CPython解释器下,如果想实现并行可以开启多个进程
二. 为何要有GIL
因为CPython解释器的垃圾回收机制不是线程安全的
三. 如何用GIL
有了GIL,应该如何处理并发 :
计算密集型:应该使用多进程
(比如: 一个工厂,需要的是员工没日没夜的工作,那么员工越多工作效率当然就高了)
from multiprocessing import Process
from threading import Thread
import os, time
def work():
res = 0
for i in range(100000000):
res *= i
if __name__ == '__main__':
l = []
print(os.cpu_count())
start = time.time()
for i in range(4):
p = Process(target=work) # 进程 耗时: 5.136266469955444
# p=Thread(target=work) # 线程 耗时: 28.20959997177124
l.append(p)
p.start()
for p in l:
p.join()
stop = time.time()
print('run time is %s' % (stop - start))
IO密集型: 应该开启多线程
(比如: 一个工厂,员工完成了 一个项目的一部分工作 就需要等待原材料运过来,那么减少员工,增加一个员工的项目量(完成一个项目的一部分工作,接着进行下一个项目) ,这样可以在保证效率的前提下,节省开销)
from multiprocessing import Process
from threading import Thread
import threading
import os, time
def work():
time.sleep(2)
if __name__ == '__main__':
l = []
start = time.time()
for i in range(4):
# p=Process(target=work) # 进程 耗时: 2.2922799587249756
p = Thread(target=work) # 线程 耗时: 2.0377535820007324
l.append(p)
p.start()
for p in l:
p.join()
stop = time.time()
print('run time is %s' % (stop - start))
四. GIL vs 自定义互斥锁:
GIL保护的是解释器级的数据,保护用户自己的数据则需要自己加锁处理,如下图:
GIL全局解释器锁并不能保护用户自己的数据,所以说 自定义互斥锁存在是合理的,当我们需要保护自己的数据时可以进行加自定义互斥锁
自定义互斥锁:
from threading import Thread,Lock
import time
mutex=Lock()
n=100
def task():
global n
with mutex:
temp=n
time.sleep(0.1)
n=temp-1
if __name__ == '__main__':
l=[]
for i in range(100):
t=Thread(target=task)
l.append(t)
t.start()
for t in l:
t.join()
print(n)