python速度慢的两大原因
- 动态类型语言,边解释边执行
- 由于GIL,无法利用多核CPU并发执行
GIL是什么?
全局解释锁(Global Interpreter Lock,GIL)是计算机程序设计语言解释器用于同部线程的一种机制,它使得任何时刻仅有一个进程在执行。即使在多核心处理器上,使用GIL的解释器也只允许同一时间执行一个线程。
在上图中的流程:
- 当线程1在运行的时候,则会启动GIL
- 当线程1需要进行IO操作时,GIL则会释放,此时线程1切换到线程2运行,GIL再次启用。
- 当线程2运行IO时,GIL再次释放,此时线程2切换到线程3,GIL则再次启用。
为什么有GIL这个东西?
为了解决多线程之间数据完整性和状态同步问题。 举例子:Python中对象的管理,是使用引用计数器进行的,引用数为0则释放对象。开始:线程A和线程B都引用了对象obj,obj.ref_num = 2,线程A和B都想撤销对obj的引用
上图中线程A和线程B都引用了对象obj, 首先,线程A准备销毁obj引用,将计数器减1,刚减完,切换到了线程B, 线程B也要销毁obj引用,将计数器减1,然后判断引用等于0,则将其释放掉。 当切换到线程A继续执行的时候,发现obj的引用已经无法获取计数器的值了。 所以,就报错了。
怎么规避GIL带来的限制?
多线程 threading 机制依然是有用的,用于IO密集型计算。因为在 I/O (read,write,send,recv,etc.)期间,线程会释放GIL,实现CPU和IO的并行。因此多线程用于IO密集型计算依然可以大幅提升速度。但是多线程用于CPU密集型计算时,只会更加拖慢速度
使用multiprocessing的多进程机制实现并行计算、利用多核CPU优势。为了应对GIL的问题,Python提供了multiprocessing
总结
- 多线程适用于IO密集型问题,当线程在处理IO问题时,将释放GIL锁,并切换至下一线程,线程的切换使用的是CPU,线程的处理使用的是IO,这样就实现了CPU和IO的并行。
- 多进程用于处理CPU密集性问题,适用于充分发挥多核CPU的优势,多进程其实变相的解决了GIL锁的弊端。