Python GIL 全局解释器锁
一、GIL概念:
全局解释器锁简称:GIL (英文:Global Interperter Lock)
GIL并不是Python语言特性,它是在现实Python解释器时引用的一个概念
,GIL仅在CPython解释器上存在
,其他解释器不一样,作用是保证同一时间内只有一个线程在执行。
二、GIL的讲解:
遵循的原则:一个线程运行Python,其它多个time.sleep()或者等待I/O,保证同一时刻只有一个线程对共享资源进行存取,简单理解,一个线程运行在一个CPU上执行字节码
。
GIL为了线程运行安全
,加了一把GIL锁,不过这使多线程执行效率不高,无法发挥核心的优势,并发性能非常的受限
。
举个简单的栗子:
import threading
total = 0
def func1():
global total
for item in range(1000000):
total += 1
def func2():
global total
for item in range(1000000):
total -= 1
thread1 = threading.Thread(target=func1)
thread2 = threading.Thread(target=func2)
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print(total)
但是输入结果并不是0,而每次的运行结果都不相同,可以得出以下结论:
协同式多任务处理:
当一项任务比如睡眠或者网络I/O启动,没有在这时间段运行任何Python代码的情况,一个线程便会让出GIL,从其它线程可以获取GIL而运行Python。这种称为协同式多任务处理,它允许并发,多个线程同时等待不同事件
。
抢占式多任务处理:
Python线程可以主动释放GIL,也可以先抓取到GIL,使得其他线程可以运行。
总结:
感觉有没有GIL都没啥影响啊,反正可以切换,那么为什么说有GIL的存在,导致Python的多线程比单线程还慢?在单核CPU下没什么不同,但是在多核CPU下问题就很大,不同核心上的线程同一个时刻只能执行一个,所以不能利用多核CPU的优势,反而不同核心间切换会造成资源浪费,反而比单核CPU更慢
。
三、GIL对程序的影响:
1.Python同一时刻只有一个线程会执行;
2.Python多个线程由于GIL锁的存在无法利用多核CPU;
3.Python多线程不适合计算机密集型的程序;
4.若程序需要大量的计算,利用多核CPU资源,可以使用多进程来解决
;
四、I/O密集型:
1.I/O密集型概念:
大部分程序运行时,都需要大量的I/O(输入/输出)操作,如网络数据的收发,大文件的读写,这样的程序称为I/O密集型程序,I/O密集型程序运行时,需要大量的时间进行等待,如果I/O操作不完成,程序就无法执行后面的操作,导致CPU空闲。
2.GIL对I/O密集型程序影响:
解释器执行Python代码时,都需要先获得这把锁才可以,在遇到I/O操作时会释放这把锁,如果是计算程序,没有I/O操作,解释器会每隔100次操作就释放这把锁,让别的线程执行,提高Python程序的执行效率
。
五、如何改善GIL的问题:
1.更换更高版本的解释器:从3.2版本开始,Python对解释器做了优化。
2.更换解释器:比如JPython,但是由于比较小众,支持模块较少,开发效率较低。
3.使用多进程代替多线程:Python为了解决使用多核的问题,可以用多进行代替多线程。
4.使用multiprocess库替代Thread库:多线程较低时,可以multiprocess库替代Thread库,即使用多进程而不是多线程,每个进程有自己的独立的GIL,因此也不会出现进程之间的GIL争抢。
六、总结:
在IO密集型操作下,多线程会得到较好的性能
在CPU密集型操作下,多线程性能反而不如单线程,这时多进程是最佳选择