python之当前GIL设计的缺陷
基于pcode数量的调度方式
按照Python社区的想法,操作系统本身的线程调度已经非常成熟稳定了,没有必要自己搞一套。所以Python的线程就是C语言的一个pthread,并通过操作系统调度算法进行调度(例如linux是CFS)。为了让各个线程能够平均利用CPU时间,python会计算当前已执行的微代码数量,达到一定阈值后就强制释放GIL。而这时也会触发一次操作系统的线程调度(当然是否真正进行上下文切换由操作系统自主决定)。
伪代码
whileTrue:
acquireGIL
foriin1000:
dosomething
releaseGIL
/*GiveOperatingSystemachancetodothreadscheduling*/
这种模式在只有一个CPU核心的情况下毫无问题。任何一个线程被唤起时都能成功获得到GIL(因为只有释放了GIL才会引发线程调度)。但当CPU有多个核心的时候,问题就来了。从伪代码可以看到,从releaseGIL到acquireGIL之间几乎是没有间隙的。所以当其他在其他核心上的线程被唤醒时,大部分情况下主线程已经又再一次获取到GIL了。这个时候被唤醒执行的线程只能白白的浪费CPU时间,看着另一个线程拿着GIL欢快的执行着。然后达到切换时间后进入待调度状态,再被唤醒,再等待,以此往复恶性循环。
PS:当然这种实现方式是原始而丑陋的,Python的每个版本中也在逐渐改进GIL和线程调度之间的互动关系。例如先尝试持有GIL在做线程上下文切换,在IO等待时释放GIL等尝试。但是无法改变的是GIL的存在使得操作系统线程调度的这个本来就昂贵的操作变得更奢侈了。
关于GIL影响的扩展阅读
为了直观的理解GIL对于多线程带来的性能影响,这里直接借用的一张测试结果图(见下图)。图中表示的是两个线程在双核CPU上得执行情况。两个线程均为CPU密集型运算线程。绿色部分表示该线程在运行,且在执行有用的计算,红色部分为线程被调度唤醒,但是无法获取GIL导致无法进行有效运算等待的时间。
GIL的存在导致多线程无法很好的立即多核CPU的并发处理能力。
那么Python的IO密集型线程能否从多线程中受益呢?我们来看下面这张测试结果。颜色代表的含义和上图一致。白色部分表示IO线程处于等待。可见,当IO线程收到数据包引起终端切换后,仍然由于一个CPU密集型线程的存在,导致无法获取GIL锁,从而进行无尽的循环等待。
简单的总结下就是:Python的多线程在多核CPU上,只对于IO密集型计算产生正面效果;而当有至少有一个CPU密集型线程存在,那么多线程效率会由于GIL而大幅下降
以上内容为大家介绍了python之当前GIL设计的缺陷,希望对大家有所帮助,如果想要了解更多Python相关知识,请关注IT培训机构:千锋教育。http://www.mobiletrain.org/

相关推荐HOT
更多>>
文本处理用c还是用python
文本处理python与c的对比:如下c++语言:C++语言实现C++中没有实现split功能的函数,下面用C++STL中的一些函数模拟实现split功能。#include#inc...详情>>
2023-11-06 23:42:24
Python什么是函数式编程?
函数式编程使用一系列的函数解决问题。函数仅接受输入并产生输出,不包含任何能影响产生输出的内部状态。任何情况下,使用相同的参数调用函数始...详情>>
2023-11-06 17:27:35
列举python常见的内置函数
abs()返回数字的绝对值map根据函数对指定序列做映射map()函数接收两个参数,一个是函数,一个是可迭代对象,map将传入的函数依次作用到序列的每...详情>>
2023-11-06 15:21:35
Python之select、poll、epoll模型的区别
select、poll、epoll模型的区别?(属于多路复用IO的模型)都是i/o多路复用的机制,监视多个socket是否发生变化,本质上都是同步i/oselect,poll实...详情>>
2023-11-06 14:44:24