Python解释器
一般使用的Python解释器CPython:是用C语言实现Pyhon,是目前应用最广泛的解释器。最新的语言特性都是在这个上面先实现,基本包含了所有第三方库支持,但是CPython有几个缺陷,一是全局锁使Python在多线程效能上表现不佳,二是CPython无法支持JIT(Just-in-time compliation即时编译),导致其执行速度不及Java和Javascipt等语言。于是出现了Pypy。
Pypy:是用Python自身实现的解释器。针对CPython的缺点进行了各方面的改良,性能得到很大的提升。最重要的一点就是Pypy集成了JIT。但是,Pypy无法支持官方的C/Python API,导致无法使用例如Numpy,Scipy等重要的第三方库。(还有JPython,IronPython等)
全局解释器锁
全局解释器锁(Global Interpreter Lock)是Python用于同步线程的工具,使得任何时刻仅有一个线程在执行。
Python GIL被动释放机制(抢占机制)
如果一个线程不间断地在 Python 2 中运行100次解释器的计步(ticks)(可以通过sys.setcheckinterval()设置计步长度),或者不间断地在 Python 3 运行15 毫秒,那么它便会放弃 GIL,而其他线程可以运行。
全局解释器锁带来的问题
多线程Python程序无法充分利用多个CPU核心带来的优势。
(主要影响CPU密集型程序,I/O密集型程序使用多线程一般是明智的选择)
解决方法
1,使用多进程
原理:每个进程分配不同的解释器,有单独的GIL。
缺点:额外产生数据序列化与通信的开销。
注意点:待执行操作需包含在以def语句定义的Python函数中(即,在这里lambda,闭包,可调用实例都是不可以的),而且函数参数和返回值必须兼容pickle编码。
使用方法:廖雪峰Python教程-多进程部分
2,使用C语言扩展模块
原理:C语言扩展程序的执行保持与Python解释器隔离,在C代码中释放GIL。
缺点:调用C函数时GIL会被锁定,若阻塞,解释器无法释放GIL。
注意点:确保C代码可以独立于Python执行。(不使用Python的数据结构,也不调用Python的C语言API)
使用方法:在C代码中插入特殊的宏或是使用其他工具来访问C代码,如ctypes库或者Cython。(ctypes默认会在调用C代码时自动释放GIL)
3,选用其他没有GIL的解释器代替CPython
原理:使用没有GIL的解释器实现。
缺点:不完全兼容。
使用方法:目前Jython和IronPython没有GIL。