python的代码执行由python虚拟机(也叫解释器主循环,CPython版本)来控制,python在设计之初就考虑到在解释器的主循环中,同时只有一个线程在运行。即在任意时刻只有一个线程在解释器中运行。对python虚拟机访问的控制由全局解释锁GIL控制,正是这个锁来控制同一时刻只有一个线程可以运行。python
在调用外部代码(如C、C++扩展函数)的时候,GIL将会被锁定,直到这个函数结束为止(因为期间没有python的字节码运行,因此不会作线程切换)。linux
在python中使用都是操做系统级别的线程,linux中使用的pthread,window使用的是其原生线程。算法
从上面的概述中能够直观的看出py在同一时刻只能跑一个线程,这样在跑多线程的状况下,只有当线程获取到全局解释器锁后才能运行,而全局解释器锁只有一个,所以即便在多核的状况下也只能发挥出单核的功能。安全
那么这样看起来py不给力啊,GIL直接致使CPython不能利用物理多核的性能加速运行。那么为何会有这样的设计?考虑到Guido van Rossum 在创造python的时候,上世纪90年代,多核cpu彻底属于不可想象的,如今因为硬件发展速度太快,程序编写就要考虑用尽cpu的所有性能,不然就要被淘汰,那么对于python一样也要如此。多线程
上面主要说的是这种设计的劣势,下面再讨论它的优点。并发
GIL的设计简化了CPython的实现,使得对象模型,包括关键的内建类型如字典,都隐式能够并发访问。锁住全局解释器使得其比较容易的实现对多线程的支持,但也折损了多处理器主机的并行计算能力。函数
可是不论标准的,仍是第三方的扩展模块,都被设计成在进行密集计算任务时释放GIL。另外还有在作IO操做时,GIL老是被释放。对全部面对内建的操做系统C代码的程序来讲,GIL会在这个IO调用以前被释放,以容许其它的线程在等待这个IO的时候运行。若是是纯计算的程序,没有IO操做,解释器会每隔100次或每隔必定时间15ms去释放GIL。性能
这里能够理解为IO密集型的python比计算密集型的程序更能利用多线程环境带来的便利。测试
多线程环境中,python虚拟机按照如下方式执行:ui
设置GIL
切换到一个线程去执行
运行代码,这里有两种机制:
指定数量的字节码指令(100个)
固定时间15ms线程主动让出控制
把线程设置为睡眠状态
解锁GIL
再次重复以上步骤
考虑用尽cpu的性能,python的应对方法很简单,在新的python3中依然有GIL,缘由大概有下几点:
CPython的GIL本意是用来保护全部全局的解释器和环境状态变量的,若是去掉GIL,就须要更多的更细粒度的锁对解释器的众多全局状态进行保护。或者采用Lock-Free算法。不管采用哪种,要作到多线程安全都会比维系一个GIL要可贵多。另外改动的仍是CPython的代码树及其各类第三方扩展也在依赖GIL。
进一步说,有人作过测试将GIL去掉,加入更细粒度的锁。可是实践检测对单线程来讲,性能更低。只有利用的物理cpu到必定数目后,性能才会比GIL版本好。且如今绝大部分的python程序都是单线程的。
自2.6引出的多进程标准库mutilprocessing,让多进程的python编写简化到相似多线程的程度,大大减轻GIL带来的诸多不利。