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)

使用ctypes访问C代码教程

 

3,选用其他没有GIL的解释器代替CPython

原理:使用没有GIL的解释器实现。

缺点:不完全兼容。

使用方法:目前Jython和IronPython没有GIL。

Jython文档IronPython官网