【python】GIL全局锁

一、原理:

全局解释器锁(Global Interpreter Lock,GIL)规定全局范围内任意时候一个进程里只能同时执行一个线程。每一个线程在执行时,都会锁住GIL,以阻止别的线程执行;执行一段时间后,会释放GIL,以允许别的线程开始利用资源,如果遇到阻塞情况,也会提前释放锁。
在这里插入图片描述

如果你的程序是单线程,该GIL锁并不会对程序造成什么影响。但如果在计算密集型的多线程代码中,GIL就是一个性能瓶颈,使Python多线程成为伪并行多线程。

“全局”的理解:

如果你的服务器拥有八核,GIL锁也就是规定8核CPU同时仅能执行一个线程,如果线程1在CPU1中运行着,线程2想在CPU2上运行,只能继续等待线程1结束,获得GIL锁,才可以在CPU2上运行。
在稍微极端一点的情况下,比如线程1使用了while True在CPU 1 上执行,那就真是“一核有难,八核围观”了,如下图所示:
在这里插入图片描述

“计算密集型”理解:

在提到开发性能瓶颈的时候,我们经常把对资源的限制分为两类,一类是计算密集型(CPU-bound),一类是 I/O 密集型(I/O-bound)。
计算密集型的程序是指的是把 CPU 资源耗尽的程序,也就是说想要提高性能速度,就需要提供更多更强的 CPU,比如矩阵运算,图片处理这类程序。
I/O 密集型的程序只的是那些花费大量时间在等待 I/O 运行结束的程序,比如从用户指定的文件中读取数据,从数据库或者从网络中读取数据,I/O 密集型的程序对 CPU 的资源需求不是很高。
对于计算密集型应用,由于CPU一直处于被占用状态,GIL锁直到规定时间才会释放,然后才会切换状态,导致多线程处于绝对的劣势,此时可以采用多进程+协程。
对于IO密集型应用,多线程的应用和多进程应用区别不大。即便有GIL存在,由于IO操作会导致GIL释放,其他线程能够获得执行权限。由于多线程的通讯成本低于多进程,因此偏向使用多线程。

何时释放锁?

在python3.2前是通过计数,默认是100,在python3.2时已经不是通过计数来切换,而是时间间隔。

C:\Users\12977>python
Python 3.9.2 (tags/v3.9.2:1a79785, Feb 19 2021, 13:44:55) [MSC v.1928 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.getswitchinterval()
0.005
>>>

https://docs.python.org/zh-cn/3.9/whatsnew/3.2.html?highlight=gil
并行运行的Python线程的序列化执行机制(通常称为GIL或全局解释器锁)已被重写。其中的目标是更可预测的切换间隔和减少由于锁争用和后续系统调用数量造成的开销。允许线程切换的“检查间隔”的概念已经被放弃,取而代之的是以秒表示的绝对持续时间。该参数可通过sys.setswitchinterval()调节。它目前默认为5毫秒。

二、GIL存在的意义:

首先了解一下引用计数这个概念。Python 使用引用计数来进行内存管理,即垃圾回收。引用计数就是说 Python 里创建的所有对象,Python 都有一个变量(reference count)记录着当前有多少个引用指向了这个对象,当引用数变成 0 的时候,Python 就会回收这个对象所占用的内存。
Python 的引用计数需要避免资源竞争的问题,我们需要在有两个或多个线程同时增加或减少引用计数的情况下,依然保证引用计数的结果是正确的。
当有多个线程同时改一个对象的引用计数的时候,有可能导致内存泄漏(对象的引用计数永远没有归零的机会),还有可能导致对象提起释放,触发莫名奇妙的 bug,程序崩溃(一个对象存在引用的情况下引用计数变成了 0,导致此对象提前释放)。
通过对不同线程访问、修改引用计数增加锁,我们就可以保证引用计数总是被正确的修改。但是,如果我们对每一个对象或者每一组对象都增加锁,这就意味在在你的 Python 程序中有很多个锁同时存在。多个锁同时存在会有其他的风险–死锁。除此之外,性能下降也是多个锁存在的一大弊端。因为申请锁和释放锁都是一笔不小的开销。
GIL 是一个锁,或者一把锁,这把锁加载了 Python 的解释器上,它要求任何 Python 代码在执行的时候需要先申请这把锁,否则就别想执行。只有一把锁,带来的好处就是 1、不会有死锁,2、对因为引入锁而导致的性能下降影响不大,然而坏处就是 GIL 这把锁让计算密集型的代码也只能使用单线程执行。

三、规避措施:

1.更换解释器:

python解释器有很多个,包括 CPython, Jython, IronPython, PyPy,分别是用 C,Java,C#,Python 实现的。但GIL 锁只存在于 CPython 解释器中。如果你的代码和依赖库不依赖 CPython 的话,那么换其他的解释器也是可行的方案。
通常加锁也有2种不同的粒度的锁:
fine-grained(所谓的细粒度), 那么程序员需要自行地加,解锁来保证线程安全
coarse-grained(所谓的粗粒度), 那么语言层面本身维护着一个全局的锁机制,用来保证线程安全
前一种方式比较典型的是 java, Jython 等, 后一种方式比较典型的是 CPython。

2.将计算型线程改写为进程:(https://docs.python.org/zh-cn/3.9/library/multiprocessing.html)

解决 GIL 锁最通用的方法是使用多进程。因为每个 Python 进程都有自己的 Python 解释器,有自己的内存空间,有自己的 GIL 锁,相互之间没有影响。自然也就没有问题了。

3.多线程调用c动态链接库,来达到多核:

通过编写C语言扩展与Python交互,在C语言层面绕过GIL实现多核利用。使用ctypes模块。

4.协程:

协程又称用户态线程,Python3.4版本后新增了对协程的支持,也是对性能的提升提供了一种选择。

四、疑问:为什么同一个多线程程序在python2中和python3中表象不一致呢?

因为Python3 针对 GIL 做了很多优化。
上面我们说性能瓶颈的时候,谈到了代码有计算密集型和 I/O 密集型,那么如果一个程序既有计算密集型又有 I/O 密集型呢?在这种情况下,Python3.0的 GIL 知道他更应该把 GIL 分给计算密集型的线程,会饿死I/ o绑定的线程。这种机制的实现原理是强制获取到GIL 锁的线程在规定的时间段长之后交出 GIL 锁,如果此时没有其他线程申请锁,那么原来的线程可以继续持有锁,继续运行。
然而这种机制带来新的问题是大部分计算密集型线程都会在其他线程申请 GIL 锁之前再次申请 GIL 锁,这会导致有些线程永远拿不到 GIL 锁(我们虽然希望 CPU 密集型的线程能相比 I/O 密集型的线程能更长时间的获得锁,但是并不希望 CPU 密集型拿着锁永远不释放)。这个问题在 Python3.2 版本中,通过引入线程没有获取到 GIL 锁的请求次数的机制解决,并且在其他线程有机会运行前,不允许当前进程重新获得GIL。

其他:
哪里可以去了解到每个python版本中做了哪些升级?
官方文档:https://docs.python.org/3/
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/6495.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

OBCP第四章 SQL调优-SQL执行性能监控

(g)v$sql_audit 全局 SQL 审计表 基于虚拟表__all_virtual_sql_audit的视图, 该虚拟表对应的数据存放在一个可配置的内存空间中 由于存放这些记录的内存是有限的,因此到达一定内存使用量,会触发淘汰 可以用来查看每次请求客户端来源&…

【操作系统复习】第3章 处理机调度与死锁 3

死锁(Deadlock):指多个进程在运行过程中因争夺资源而造成的一种僵局,当进程处于这种僵持状态时,若无外力作用,这些进程都将永远不能再向前推进。 对资源不加限制地分配可能导致进程间由于竞争资源而相互制约…

JavaSE学习总结(十三)Set集合HashSet集合LinkedHashSet集合TreeSet集合比较器的使用利用Set集合实现去重

JavaSE学习总结(十三)Set集合/HashSet集合/LinkedHashSet集合/TreeSet集合/比较器的使用/利用Set集合实现去重 一、Set集合 Set集合是Collection集合的一个子接口,实际上Set就是Collection,只是行为略有不同: Set集…

VUE3项目实现动态路由demo

文章目录1、创建vue项目2、安装常用的依赖2.1 安装elementUI2.2 安装axios2.3 安装router2.4 安装vuex2.5 安装store2.6 安装mockjs3、编写登录页面以及逻辑4、编写首页以及逻辑5、配置router.js6、配置store.js7、配置menuUtils.js(动态路由重点)8、配置…

树的前序遍历与中序遍历构造二叉树和树的中序遍历与后序遍历构造二叉树

目录 一.树的前序遍历与中序遍历构造二叉树 1.题目描述 2.问题分析 3.代码实现 二.树的中序遍历与后序遍历构造二叉树 1.题目描述 2.问题分析 3.代码实现 三.问题思考 一.树的前序遍历与中序遍历构造二叉树 1.题目描述 给定两个整数数组 preorder 和 inorder &#xf…

【机器学习】Logistic回归---学习笔记

Logistic回归学习笔记Logistic回归学习线路预备知识:建议先去B站学习一下信息量,熵,BL散度,交叉熵的概念。Logistic回归的函数模型损失最小化架构分类函数最大概率分类函数阈值分类函数Logistic回归的优化算法梯度下降随机梯度下降…

4.5--计算机网络之基础篇--2.网址到网页解析--(复习+深入)---好好沉淀,加油呀

1.浏览器做的第一步工作是解析 URL 对 URL 进行解析,从而生成发送给 Web 服务器的请求信息 URL? URL 实际上是请求服务器里的文件资源 当没有路径名时,就代表访问根目录下事先设置的默认文件,也就是 /index.html 或者 /default.html 这些文件…

计算机网络复习笔记(三)物理层

文章目录一物理层的基本概念四大特性:两种信号:调制和编码传输介质三大部分二物理层的基本通信技术四种信道复用技术数据的传输方式三OSI模型一物理层的基本概念 四大特性: 机械特性 接口是怎么样的 电气特性 用多少伏的电 功能特性 线路上…

linux基础之计算机基础

一、计算机基础 (1) 计算机发展:电子管、晶体管、集成电路、大规模集成电路 (2) 冯诺依曼体系:用二进制表示数据和指令; 存储程序控制,程序和数据预先存入存储器; 计算机系统5大部分&#xf…

Python 高级编程(文件操作)

文件:存储在某种长期存储设备上的数据!!包括(硬板 u 盘 移动硬盘 光盘) 计算机中临时的数据: 存储在内存中,一旦操作结束,内存中的空间就会被释放 文件(特指普通文本&am…

R语言 4.2.2安装包下载及安装教程

[软件名称]:R语言 4.2.2 [软件大小]: 75.6 MB [安装环境]: Win11/Win10/Win7 [软件安装包下载]: https://pan.quark.cn/s/b6f604930d04 R语言软件的GUI界面比较的简陋,只有一个命令行窗口,且每次创建图片都会跳出一个新的窗口,比较的繁琐,我们可以安装RStudio,来更方便的操作R(…

ChatGPT +工业机器人/自动驾驶控制器的一些尝试

ChatGPT 的功能目前已扩展到机器人领域,可以用语言直观控制如机械臂、无人机、家庭辅助机器人等的多个平台。这会改变人机交互的未来形式吗? 你可曾想过用自己的话告诉机器人该做什么,就像对人说话那样? 比如说,只要告…

多个硬盘挂载到同一个目录

同一目录无法重复挂载,后挂载的会覆盖之前挂载的磁盘。但是现在需要将4块磁盘并行挂载,该如何操作呢? 将2块磁盘合并到一个逻辑卷 进行挂载。 基本知识 基本概念PV(Physical Volume)- 物理卷物理卷在逻辑卷管理中处于最底层,它可…

新能源锂电池行业除杂工艺介绍

近年来新能源汽车快速发展对锂电池的需求引发了人们对锂资源的高度关注。由于锂需求不断上升,全球锂资源越来越紧缺,而在生产含锂产品中会有大量废水、废渣。这些废水废渣含有丰富的锂,对其进行回收提锂具有极高的经济利益。在氟化锂生产中会…

文件操作介绍及C语言实现通讯录管理系统3.0最终版(文件操作版本)

文章目录1. 前言2. 文件操作2.1 什么是文件2.2 文件缓冲区2.3 文件指针2.4 文件的打开与关闭2.5 文件的顺序读写3. 优化通讯录3.1 保存通讯录3.2 加载通讯录4. 结尾1. 前言 上一篇文章我们学习了动态内存开辟的相关知识点,并用动态内存函数优化了我们的通讯录&…

【数据库连接,线程,ThreadLocal三者之间的关系】

一、数据库连接与线程的关系 在实际项目中,数据库连接是很宝贵的资源,以MySQL为例,一台MySQL服务器最大连接数默认是100, 最大可以达到16384。但现实中最多是到200,再多MySQL服务器就承受不住了。因为mysql连接用的是tcp协议&…

JAVA:常用API

一.什么是API? API(Application Programming Interface):应用程序编程接口。 简单的来说:就是Java帮我们已经写好的方法,我们可以直接使用。 二.有哪些常用的API? Object、Objects、StringB…

二战华为成功上岸,准备了小半年,要个27k应该也算不上很高吧~

先说下我基本情况,本科不是计算机专业,现在是学通信,然后做图像处理,可能面试官看我不是科班出身没有问太多计算机相关的问题,因为第一次找工作,华为的游戏专场又是最早开始的,就投递了&#xf…

二,八,十,十六进制等常用进制详解

总目录 文章目录总目录一、常用进制1、进制基本信息2、各进制的表示形式二、进制转换原理1、其他进制转为十进制计算原理2、十进制转为其他进制计算原理3、二进制,八进制,十六进制之间的转换结语一、常用进制 1、进制基本信息 基数数码名称描述20 和 1…

【C++】| C/C++内存管理

前言: 在上期,我们已经对类和对象的全部知识进行了总结和梳理。在类和对象学习完之后,今天我将给大家呈现的是关于——C/C内存管理的基本知识。 本文目录 1. C/C内存分布 2. C语言中动态内存管理方式 (1)C语言跟内…