Python全局锁(GIL)
题记
使用threading进行多线程处理的时候,运算速度并没有提高。原因在于python中的全局锁(GIL, global interpreter lock).
样例
计算圆周率的程序
代码
点击展开代码
|
|
结果
~/dataset/xiaoaiKWS/G/code$ python3 测试多线程速度.py
multi 多线程
3.140688
Run time 83.02815461158752
3.1416188
Run time 85.89040064811707
3.1412312
Run time 86.34525346755981
3.14129
Run time 88.51046800613403
3.1419212
Run time 88.64371156692505
Run time 88.65449285507202
single
3.1421216
Run time 10.199804782867432
3.1420676
Run time 10.172762870788574
3.1419712
Run time 10.3925302028656
3.1417784
Run time 10.204853534698486
3.1416324
Run time 10.210267305374146
Run time 51.180365800857544
启示
多线程速度要慢于串行,多线程不适合cpu密集型程序(但是可以用在IO密集的程序里).
GIL
参考: http://cenalulu.github.io/python/gil-in-python/
https://zhuanlan.zhihu.com/p/20953544
为什么有GIL
GIL是线程之间的排他锁(官方文档使用mutex
这个词),用于保持线程间数据的一致性和状态的同步(这本身是一个非常难的议题, MySQL用了五年时间优化,而python作为高度社区化团队开发为解决这个问题更为艰难),而GIL是一种非常简单粗暴但是优雅的方法.
图解多线程
GIL释放条件
- 在python2.x里,GIL的释放逻辑是当前线程遇见IO操作或者ticks计数达到100(ticks可以看作是python自身的一个计数器,专门做用于GIL,每次释放后归零,这个计数可以通过 sys.setcheckinterval 来调整),进行释放.
- 在python3.x中,GIL不使用ticks计数,改为使用计时器(执行时间达到阈值后,当前线程释放GIL),这样对CPU密集型程序更加友好,但依然没有解决GIL导致的同一时间只能执行一个线程的问题,所以效率依然不尽如人意.
两个线程在双核CPU上的执行情况.
-
绿色部分表示该线程在运行
-
红色部分为线程被调度唤醒,但是无法获取GIL导致无法进行有效运算等待的时间
-
白色部分表示IO线程处于等待
两个线程均为CPU密集型运算线程
一个IO密集型和一个CPU密集型线程
IO密集型代码(文件处理、网络爬虫等),多线程能够有效提升效率(单线程下有IO操作会进行IO等待,造成不必要的时间浪费,而开启多线程能在线程A等待时,自动切换到线程B,可以不浪费CPU的资源,从而能提升程序执行效率)。所以python的多线程对IO密集型代码比较友好。
结论
python尽量使用多进程 (使用python multiprocessing模块),而不是多线程,因为每个进程有各自独立的GIL,互不干扰,这样就可以真正意义上的并行执行.
扩展资料
IO同步和异步,阻塞和非阻塞 https://juejin.im/post/5b94e2995188255c5c45d0ec
廖雪峰python3多进程多线程 (适合代码学习) https://www.liaoxuefeng.com/wiki/1016959663602400/1017628290184064