首页 > 数据库 > 数据库开发技术 > Python线程前置知识点-GIL全局解析器
关于python多线程处理并发的话,这里就不得不再提一次GIL,之前也有提过关于这个GIL的一下简单介绍,这里也为了完整性,这里也复述一下。

我们的知道我们的线程执行的是可以如果是在多核的的情况下,是可以分配到多核上进行执行的。如:java的多线程如果是在多核的情况下是可以分别在多核上进行执行的。
但是python的因为历史原因,久久未能把这个历史遗留的问题给处理,估计后续也不会处理了!
但是对于GIL的认知,需要梳理清楚几个问题:
说简单点就是,因为我们的python内存管理机制采用了引用计数的方式来处理垃圾回收,为了相关统计引用,以及方便进行数据管理,相关的Cpython解析器,规定:某个线程的执行,必须先要拿到GIL(全局解释锁)。
当我们的一个python程序跑起来之后,就会形成一个python程序进程,这个进程纸只有且只有一个GIL,在这个进程中的线程,如果需要执行,需要获取先拿到GIL 全局解释器锁。
如,一个四线程的程序,跑在一个四核的CPU上的话:
因为python调用操作系统的底层C语音的原生接口,就只是C的原生线程,在都多线程的情况在修改数据的时候,为了防止数据改乱了,在出口做了设置,把多线程执行变为串行处理,也就是所谓的全局解释器锁,保证了数据统一和安全。
PS:GIL并不是Python的特性,它是在实现Python解析器(CPython)时所引入的一个概念,是相关python解析器所有。
所以,解释器加锁以后:
线程的执行其实是串行,或(微观上的并发执行),GIL上锁后意味着同一时间只有一个CPU在处理你的线程。
官方的说法是:
在cpython中,gil是一个互斥锁,用来保护对python对象的访问,防止多个线程同时执行python字节码。
在CPython的线程是操作系统的原生线程,在Linux的pthread完全由操作系统调度执行。pthread本身不是线程安全的,所以如果需要进行保证数据一致性,需要使用者通过锁来实现保证多线程的安全运行,因此CPython解释器下的Python实现多线程也必然存在线程不安全的问题。
所以,多线程下执行python字节码的情况下,所以加GIL这个锁(然而,由于GIL的存在,其他新增的特性,为了省事都在默认线程安全的前提下进行,导致GIL成了不可或缺的依赖。)
所以从官网说辞可以知道是引入的主要原因历史遗留原因:
1:首先并发变成的需求是,随着CPU发展而来的。所以我们的多线程编程也是是随着多核CPU发展而发展,但早起我们的cpython都是基于都是在单核CPU的前提下设计的,没考虑过多核的情况。
2:cpython在并发的需求情况下,为了利用多核,Python也开始支持多线程,但是它的内存管理不是线程安全的,为了解决多线程之间数据完整性和状态同步的,最简单方法自然就是加锁,为了更好进行内存更好的进行管理所以只能加GIL这个全局锁。
Jython 一种由java语言编写的python解释器,是将python编译成Java字节码然后执行的一种解释器,可以方便地和Java的类库进行交互。
IronPython 将Python代码解释为.Net平台上运行的字节码进行执行,类似Jython解释器,可以方便的和.Net平台上的类库进行交互。
IPython
在交互效果上有所增强,但执行过程和功能方面和CPython是一样的。
一种使用JIT(just-in-time)技术的编译器,专注于执行速度,对Python代码进行动态编译,从而提高Python的执行速度。
PS:PyPy在处理python代码的过程中,一小部分功能的处理和CPython的执行结果是有差异的,如果用PyPy建议先了解下PyPy和CPython的区别。
CPython是主流版本的解释器,这个解释器是使用C语言编写的,也是使用最为广泛的解释器,可以方便地和C/C++的类库进行交互。
Python是一门动态语言,它是边解释边执行的
整个过程就是:执行过程中:源代码-->字节码-->机器码,整个过程由是Python解释器处理完成的。
早期的GIL的执行机制是:
后期的GIL的执行机制是:
原因是:
多核情况下多线程执行时,计数器模式存在缺陷,当一个线程在CPU-1执行完之后释放GIL之后,存在一定的概率,又被自己把锁给抢夺回来
而此时其他CPU线程可能被唤醒后,进行竞争的申请锁,发现锁还在别的线程那,浪费了,并且有可能会一直得不到锁的情况。
多核CPU频繁进行线程切换.
按执行照字节码指令数来统计,有些指令码简单执行快,,有些很复杂,导致计数也存在缺陷
升级后:
通常我们对于任务的执行分:IO密集型和CPU计算密集型。
PS:CPU性能的具体作用的体现:
而对于任务作业的这些我们的执行程序执行通常有两种状态:
通常我们的python中的线程如果遇到的IO的时候,会自动的进行GIL锁就的释放,让给其他的线程执行。
GIL不能保证自己开启的线程安全,但能保证解释器中的数据是线程安全。(嫌贵与解锁器对象而言)
GIL 在线程调用解释器时,会进行自动加锁,而在线程遇到IO阻塞时或线程代码执行完毕时会进行自动解锁。
线程互斥锁- 是相对于程序内部的相关的数据对象而言,锁的是程序内部操作的资源对象。
GIL锁的python字节码执行码
multiprocess库的出现很大程度上是为了弥补thread库因为GIL而低效的缺陷。
它完整的复制了一套thread所提供的接口方便迁移。 每个进程有自己的独立的GIL,因此也不会出现进程之间的GIL争抢,通过多进程的方式绕过GIL。
个人其他博客地址
简书:https://www.jianshu.com/u/d6960089b087
掘金:https://juejin.cn/user/2963939079225608
小钟同学 | 文 【原创】| QQ:308711822
1:本文相关描述主要是个人的认知和见解,如有不当之处,还望各位大佬指正。 2:关于文章内容,有部分内容参考自互联网整理,如有链接会声明标注;如没有及时标注备注的链接的,如有侵权请联系,我会立即删除处理哟。
原文作者:程序员小钟同学;如有侵权,请联系管理员删除。