为什么python的多线程不能利用多核CPU,但是咱们在写代码的时候,多线程的确是在并发,而且还比单线程快。

python里的多线程是单cpu意义上的多线程,它和多cpu上的多线程有着本质的区别。
单cpu多线程:并发
多cpu多线程:并行内部包含并发

首先强调背景:
1、GIL是什么?
GIL的全称是Global Interpreter Lock(全局解释器锁),来源是python设计之初的考虑,为了数据安全所做的决定。
2、每个CPU在同一时间只能执行一个线程(在单核CPU下的多线程其实都只是并发,不是并行,并发和并行从宏观上来讲都是同时处理多路请求的概念。但并发和并行又有区别,并行是指两个或者多个事件在同一时刻发生;而并发是指两个或多个事件在同一时间间隔内发生。)

在Python多线程下,每个线程的执行方式:
1、获取GIL
2、执行代码直到sleep或者是python虚拟机将其挂起。
3、释放GIL

可见,某个线程想要执行,必须先拿到GIL,我们可以把GIL看作是“通行证”,并且在一个python进程中,GIL只有一个。拿不到通行证的线程,就不允许进入CPU执行。

...
Py_begin_allow_threads
sleep((int)secs);
Py_end_allow-threads
...
这段代码是sleep的代码,在执行sleep之前,通过一个宏来释放GIL,然后在睡眠结束执行其他代码前又获取GIL。其他一下操作,比如IO,也会有类似的操作,这样就使得对于IO密集型的程序,或者是使用C库进行计算的程序,还是可以在很大程度上避开GIL来取得线程并行的效果的。但对于纯python代码的程序,GIL恐怕还是躲不过去的。
还有一个问题,就是GIL怎么释放,我们看到在python/C API中提供了宏来进行释放,那么对于普通的python语句呢?解释器会在执行一百条python代码后强制释放GIL,这就使得其它线程得以执行
最后需要说明的,就是这个GIL的问题是解释器相关的,而不是语言相关的。也就是说它只是对于python语言解释器的一种实现,并不是语言本身的特性。事实上,GIL就是解释器的一个非常粗粒度的锁,我们完全可以采用更细粒度的锁来增加并行性,而且Gindo就写过一个patch来取消GIL,不过好像最后的结果是细粒度锁导致了单线程程序的性能下降了两倍,所以最后还是决定优先保证单线程程序的性能,继续保留GIL。但是python的其他两个分支,Jython和IronPython,却都没有GIL的问题,从而可以实现线程的并行。为什么呢?这里也不知道原因了。


python追求的是简单和简洁.在代码中加入多线程往往都是一件简单的事情.这违背了python里面的蝉.提供了多线程不代表他就是常规理解的多线程.和ruby一样,ruby也提供了多线程但是确实伪线程.


1. 准确的说,只有获得了GIL的线程可以执行Python ByteCode,也就是说,Python ByteCode不能并行在多核上运行。但是Python里有大量的C代码,这些代码可以不受GIL的限制。
2. 谁说并行一定要多线程?早在没有线程那会儿Unix甚至Windows就并行的好好的了,连DOS下都有TSR。就算是纯Python,你一样可以用multiprocess做并行,一样能把CPU跑满。

猜你喜欢

转载自www.cnblogs.com/Brunce/p/9123810.html