Python GIL 一文全知道!
GIL 作为 Python 开发者心中永远的痛,在最近即将到来的更新中,终于要彻底解决了,整个 Python 社群都沸腾了
什么是GIL?
GIL是英文学名global interpreter lock的缩写,中文翻译成全局解释器锁。GIL需要解决的是线程竞争(thread racing)的问题,所以需要理解GIL的作用机制,我们需要了解一些简单的背景知识,包括程序在计算机上运行的机制,线程和进程的区别,还有并行和并发的概念。
程序在计算机上是如何运行的?
我们的程序代码是存储在硬盘上,当启动程序时,cpu会为应用程序启动进程(process),小应用程序只需要一条进程,但大的应用程序如Google Chrome在后台会启动多条进程,对应不同的服务。
每条进程都是独立的运行单元,计算机会为每条进程分配内存空间,并提供必要的计算资源。我们的程序代码在启动进程时会被加载到这个特定的内存区块里作为数据资源供计算机cpu调用。
为了更好地理解,这里我们可以把进程想象成高速路上的某条车道,那线程(thread)自然就是车道上跑的汽车。一个程序可以以单线程的方式运行,就像只有一辆车在车道上跑,当然也可以以多线程的方式运行,这就像很多车在同一车道上跑。
进程之间是相对独立运行的,而在同一进程上运行的线程之间是共享内存的。这是进程和线程最大的区别,这个区别意味着开启多个进程会消耗更多的内存,但开启多个线程不会额外增加内存负担。
另外,如果一条进程挂了,其它进程继续照常运行,但如果一条线程挂了,相应的进程也会挂掉,运行在该进程上的所有线程自然也会跟着挂掉。
这就好比,在高速路上,如果车道1(进程的比照)出现交通事故,那整条车道都将不能使用,但这并不影响其它车道(其它进程继续运行)的正常运行。同样的道理,如果在车道1上有一辆车(线程的比照)发生故障停在车道上不能动了(线程挂了),那其它车辆也不能行驶了,这条车道暂停服务进入交通管制状态(进程挂了),直到故障车被拉出车道,管制消除,车道继续畅通运行(进程重启)。
并行和并发的区别?
理解了进程和线程,并行和并发就很好理解了。
并行和并发是计算机处理任务的两种不同模式。
在并行模式(parallelism)下,多任务可以同时运行,提高了计算机的性能。这里要注意一点,要真正实现并行,程序必须在多核机器上运行,并行任务同时运行在不同的cpu上,在时间片轮上是可以重叠的,如下图中Task 1和Task 3。但我们来看Task 1和Task 2是跑在同一个cpu上的,而且它们是交替进行,这种模式就是并发模式。还有一点很重要,这个问题曾经让我困惑很久。那就是并行模式理论上可以通过多线程并行也可以通过多进程并行。
多进程并行就是在每个cpu上启动新的进程,每个进程都需要分配独立内存空间,而多线程并行是在每个cpu中启动新的线程,该线程共享主线程的内存空间。由于Python GIL的限制,在Python环境中,并行只能通过多进程的模式,而其它语言如Java,C等可以通过多线程的方式进行并行运算。
并发模式(concurrency)基于线程机制,计算机将多个任务分配给在同一进程中的不同线程进行运行,不过在并发模式下多线程不能同时处理任务,但也不是像单线程一样,一个接着一个处理,而是通过交替循环。如上图所示,假设有两个任务Task 1和Task 2分别运行在线程A和B上,在并发模式下,线程A运行一小段时间后cpu把它挂起,并切换到线程B,线程B又运行一小段时间后被挂起,同时切换回线程A,如此循环,直到任务完成。
在实践中,并行和并发不是非此即彼,根据任务的不同程序的运行可以被合理配置,最大程度地利用计算机上的cpu资源。还是用上面的图来举例,我们将任务分成两个平行的任务单元,并将这两个任务单元分配给两个cpu进行并行运算,同时在每个cpu里,任务单位再细分为两个更小的任务(Task 1和Task 2,以及Task 3 和Task 4),这两个小任务将在各个cpu里两个线程中并发运行。
除了这种任务配置模式,还可以有其它的配置方案,比如可以让每个任务单元在某些cpu上进行单线程运行,在某些cpu上开多线程并发运行,这取决于可支配的cpu资源、需要完成的任务的类型以及任务之间的耦合性,需要具体问题具体分析。
那并行和并发运行模式分别适合于什么样的场景呢?
首先计算机所处理的任务大致可以分为计算密集型和IO密集型任务。
计算密集型顾名思义需要大量的cpu算力,比如人工智能模型里大型矩阵运算,图形处理等;而IO密集型任务,是指磁盘IO、网络IO占主要的任务,计算量很小,不需要消耗太多计算资源,大部分在等待的状态,比如向服务器请求数据,线程要等待服务器的响应。
如果我们的任务都是计算密集型的,通过多线程并发模式运行程序并不能带来性能的提高,可能反而比单线程下所花的时间更长,因为首先并发不是同时处理任务,而是短时轮流循环执行子任务,并且在线程切换时需要额外消耗计算机资源,这样情况适合多任务并行运算。
如果计算机需要处理的是IO密集型任务,这时如果用并行模式,我们会浪费很多cpu资源,因为处理IO密集型任务不需要太多计算资源,大部分时间是在等待,所以这种情况适合用单cpu并发模式,好处是只用一个cpu资源,通过交替执行任务,可以在IO任务中的等待时间区间里切换线程去执行其它IO任务,从而更充分地利用了cpu资源。
还有一种情况,如果我们需要处理的任务既有计算密集型任务又有IO密集型任务,那我们可以考虑同时用并行和并发,在分配任务单元时,将计算密集型和IO密集型任务进行混合,如此单个cpu上既有有计算密集型又有IO密集型任务,那采用多线程并发就会极大地提高计算机运行效率,原因是计算机在处理IO密集任务时不需要浪费等待的时间,在IO阻塞的情况,切换线程到计算密集任务,这就用IO等待时间来处理其它计算密集型任务,从而提高程序运行效率。
Python语言中的GIL
Python的解释器是CPython,CPython本身并不确保线程安全(thread safe),也就是解释器不会对多个线程对同一个python对象的操作行为进行约束。这里我们来举个例子。在这个例子中,我们考虑两个线程(1和2)共享同一个变量a,a的初始值为1。我们可以允许两个线程以任何顺序对变量a进行两种写操作,其中,在线程1中,我们修改a的值 a= a+2 ,在线程2中,我们也修改a的值 a = a*2 。取决于两个写操作的顺序,我们可以有以下几种不同情况。
情况一, a= a+2 —> a = a*2 a的最终值为6
情况二, a= a * 2 —> a = a+2 这种情况下的a的最终值为4
情况三,线程1和线程2同时获取变量a,那结果就取决于哪条线程最后修改a的值,如果线程1后修改a的值,那a的最终值就是3,如果线程2后修改a的值,那a的最终值是2。
这三种情况都有可能发生,所以每次运行程序前我们都无法预知a的最终值,这是由于线程竞争带来的side effect,虽然程序员在正常情况下都不会去做线程不安全的操作,即两个线程可以同时以任何顺序修改一个共有变量,但如果对多线程的任务执行顺序不加限制,这种错误在理论上是可能发生的,特别是当业务代码量很大又有多个程序员同时维护开发代码时,犯这种错误的可能性变大。
要避免这种线程不安全的编程行为,要么对程序员的编程行为进行约束(比如Java中有多线程并行编程的一系列安全规范),要么在编程语言层面上设计一种机制杜绝这种不安全的线程行为,Python中的GIT就是提供了这种机制。
GIT的概念很简单,GIT是个全局变量,被所有线程共享。并且,GIT在特定的时刻只允许被一条线程获取,获取GIT锁的线程就拥有执行任务的权限,而其它线程必须先获取GIT锁才可以执行线程任务。
这样一来,Python就断了多线程并行的路子。在Python里,多线程只能并发。如果需要并行,只能通过多进程的模式,具体实现通过内置库multiprocessing。
删除 GIL
现在,Python 团队已经正式接受了删除 GIL 的这个提议,并将其设置为可选模式,可谓是利好广大开发者。
做出这一贡献的是一位来自 Meta 的名叫 Sam Gross 的软件工程师,他花费了四年多的时间才完成这一工程。
在得知这一消息后,大家纷纷叫好,深度学习三巨头之一的 Yann LeCun 发文祝贺:没有了 GIL,现在,Python 代码可以自由的执行多线程了。
CPython 核心开发者 Thomas Wouters 撰文描述了 Python 中的无 GIL 细节,并对未来发展做了展望。
原文翻译如下:
非常感谢所有人对无 GIL 提议的反馈,整体上都持积极的支持态度。指导委员会打算接受无 GIL 提议,并就以下具体细节与大家分享。
我们的基本设想是:
- 长期来看(大约 5 年以上),no-GIL 构建应是唯一的构建;
- 我们希望非常谨慎地对待向后兼容。我们不希望出现另一个 Python 3 的情况,所有适应 no-GIL 构建所需的第三方代码更改应只适用于 with-GIL 构建(尽管仍要解决更老 Python 版本的向后兼容性问题)。这不适用于 Python 4。我们仍在考虑对这两个构建的 ABI 兼容性和其他细节的要求,以及对向后兼容性的影响;
- 在我们承诺完全转向 no-GIL 之前,希望看到社区的支持。我们不能只是更改默认设置,更希望社区弄清自己做什么工作来给予我们支持。我们核心开发团队需要获得新构建模式及相关所有内容的经验。我们要整理现有代码中的线程安全性,需要弄明白新的 C API 和 Python API。我们在获得这些洞见时还需要传达给 Python 社区的其他人,并确保自身想要做出的更改以及希望其他人做出的更改是可取的;
- 在我们默认 no-GIL 设置之前的任何时候,如果事实证明了,它的破坏性太大导致收益太少,我们希望能够改变主意。这也就意味着我们会回滚所有工作,因此在我们确定要将 no-GIL 设为默认方式之前,特定于 no-GIL 的代码在某种程度上应是可识别的。
目前,我们认为未来的道路分为以下三个阶段:
- 短期内,我们会将 no-GIL 构建作为一种实验性构建模式,大概会在 3.13 版本(也有可能推迟到 3.14 版本)可用。之所以是实验性的,是因为我们核心开发团队虽然支持这一构建模式,但不期望整个社区都会支持它。我们需要时间理清自己要做什么,至少在 API 设计以及打包和分发方面,从而得到社区的支持。我们也不鼓励 distributor 将实验性 no-GIL 构建作为默认解释器发布。
- 中期来看,在我们确信得到足够的社区支持并使 no-GIL 的生产使用可行后,我们将支持 no-GIL 构建,但不是默认方式,而是在某个目标日期或某个 Python 版本中使它成为默认方式。具体的时间将取决于很多因素,比如 API 更改最终的兼容性如何、社区认为他们仍然需要做多少工作等。我们预计这至少需要一至两年的时间。一旦我们宣布支持,预计将有一些 distributor 会开始默认发布 no-GIL。
- 长期来看,我们希望 no-GIL 成为默认方式,并删除 GIL 的所有痕迹(但不会不必要地破坏向后兼容性)。我们不希望等太长时间,毕竟两种常用的构建模式同时存在会给社区造成很大的负担(比如需要双倍测试资源和 debug 场景)。但是我们也不能急于求成。我们认为这一过程将需要花费五年的时间。
当然在整个过程中,我们整个开发团队将需要实时评估进程并对时间线进行调整。
评论区的小伙伴们,你们对 GIL 成为可选是什么看法呢?
相关文章:

Python GIL 一文全知道!
GIL 作为 Python 开发者心中永远的痛,在最近即将到来的更新中,终于要彻底解决了,整个 Python 社群都沸腾了 什么是GIL? GIL是英文学名global interpreter lock的缩写,中文翻译成全局解释器锁。GIL需要解决的是线程竞…...

数据库级别的MD5加密(扩展)
首先,我们要知道什么是MD5? 1.主要是增强算法的复杂性和不可逆性 2.MD5不可逆,具体的值MD5是一样的 3.MD5破解网站的原理,背后有一个字典 代码案例: -- 加密 update testMD5 set pwdmd5(pwd) where id1; update testMD5 set…...

Docker安装Jenkins,配置Maven和Java
前言 这是一个java的springboot项目,使用maven构建 安装准备 需要将maven和jdk安装在服务器上,Jenkins需要用到,还有创建一个jenkins的目录,安装命令如下: docker run -d -uroot -p 9095:8080 -p 50000:50000 --n…...
游戏分组(100用例)C卷 (JavaPythonC语言C++Node.js)
部门准备举办一场王者荣耀表演赛,有10名游戏爱好者参与,分为两队,每队5人。 每位参与者都有一个评分,代表着他的游戏水平。为了表演赛尽可能精彩,我们需要把10名参赛者分为实力尽量相近的两队。一队的实力可以表示为这一队5名队员的评分总和。 现在给你10名参与者的游戏水…...
python函数装饰器保存信息
1 python函数装饰器保存信息 python函数装饰器,可以通过实例属性、全局变量、非局部变量和函数属性,来保存被装饰函数的状态信息。 1.1 统计调用并跟踪 描述 通过装饰器统计函数调用次数,并且用打印来跟踪调用记录。 此装饰器用类的__ca…...
AI真正的Killer App 仍然缺席
每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…...

Docker 镜像以及镜像分层
Docker 镜像以及镜像分层 1 什么是镜像2 Docker镜像加载原理2.1 UnionFs:联合文件系统2.2 Docker镜像加载原理2.3 Docker镜像的特点 3 镜像的分层结构4 可写的容器层 1 什么是镜像 镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行…...
aigc 启动器 sd-webui-aki-v4 decode_base64_to_file
下载地址: SD-WebUI启动器 绘世-启动器 | 万物档案 decode_base64_to_file报错: File "E:\BaiduNetdiskDownload\stable diffusion\sd-webui-aki-v4\extensions\sd-webui-controlnet\scripts\external_code.py", line 7, in <module>fr…...

【C++进阶05】AVL树的介绍及模拟实现
一、AVL树的概念 二叉搜索树的缺点 二叉搜索树虽可以缩短查找效率 但如果数据有序或接近有序 二叉搜索树将退化为单支树 查找元素相当于在顺序表中搜索元素,效率低下 AVL树便是解决此问题 向二叉搜索树中插入新结点 并保证每个结点的左右子树 高度之差的绝对值不超…...

MySQL视图 索引 面试题
一. 视图 视图:一种虚拟存在的表,行和列的数据来自定义视图的查询中使用的表,并且是在使用视图时动态生成的,只保存了sql逻辑,不保存查询结果 视图语法 -- 创建 create view 视图名 as 查询语句;-- 使用 select * f…...

JAVA实现文件上传至阿里云
注册阿里云账号后,开通好对象存储服务(OSS),三个月试用 阿里云登录页 (aliyun.com) 目录 一.创建Bucket 二.获取AccessKey(密钥) 三.参考官方SDK文件,编写入门程序 1.复制阿里云OSS依赖,粘贴…...

设计模式之外观模式【结构型模式】
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档> 学习的最大理由是想摆脱平庸,早一天就多一份人生的精彩;迟一天就多一天平庸的困扰。各位小伙伴,如果您: 想系统/深入学习某…...

Qt QCheckBox复选按钮控件
文章目录 1 属性和方法1.1 文本1.2 三态1.3 自动排他1.4 信号和槽 2 实例2.1 布局2.2 代码实现 Qt中的复选按钮类是QCheckBox它和单选按钮很相似,单选按钮常用在“多选一”的场景,而复选按钮常用在"多选多"的场景比如喜欢的水果选项中…...

加速科技ST2500 数模混合信号测试设备累计装机量突破500台!
国产数字机,测试中国芯!新年伊始,国产半导体测试设备领军企业加速科技迎来了振奋人心的一刻,ST2500 数模混合信号测试设备累计装机量突破500台!加速科技凭借其持续的创新能力、完善的解决方案能力、专业热忱的本地化服…...

ASP.NETCore WebAPI 入门 杨中科
ASP.NETCore WebAPI入门1 回顾 mvc开发模式 前端代码和后端代码是混在一个项目之中 WEB API 1、什么是结构化的Http接口。Json。 2、Web API项目的搭建。 3、Web API项目没有Views文件夹。 4、运行项目,解读代码结构。 5、【启用OpenAPI支持】→>swagger,在界…...
问题 C: 活动选择
题目描述 学校在最近几天有n个活动,这些活动都需要使用学校的大礼堂,在同一时间,礼堂只能被一个活动使。由于有些活动时间上有冲突,学校办公室人员只好让一些活动放弃使用礼堂而使用其他教室。 现在给出n个活动使用礼堂的起…...

SpringBoot学习(五)-Spring Security配置与应用
注:此为笔者学习狂神说SpringBoot的笔记,其中包含个人的笔记和理解,仅做学习笔记之用,更多详细资讯请出门左拐B站:狂神说!!! Spring Security Spring Security是一个基于Java的开源框架,用于在Java应用程…...
Java解决删除子串后的字符串最小长度
Java解决删除子串后的字符串最小长度 01 题目 给你一个仅由 大写 英文字符组成的字符串 s 。 你可以对此字符串执行一些操作,在每一步操作中,你可以从 s 中删除 任一个 "AB" 或 "CD" 子字符串。 通过执行操作,删除所…...

日志系统一(elasticsearch+filebeat+logstash+kibana)
目录 一、es集群部署 安装java环境 部署es集群 安装IK分词器插件 二、filebeat安装(docker方式) 三、logstash部署 四、kibana部署 背景:因业务需求需要将nginx、java、ingress日志进行收集。 架构:filebeatlogstasheskib…...

游戏版 ChatGPT,要用 AI 角色完善生成工具实现 NPC 自由
微软与 AI 初创公司 Inworld 合作,推出基于 AI 的角色引擎和 Copilot 助理,旨在提升游戏中 NPC 的交互力和生命力,提升游戏体验。Inworld 致力于打造拥有灵魂的 NPC,通过生成式 AI 驱动 NPC 行为,使其动态响应玩家操作…...

第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...

idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...

XCTF-web-easyupload
试了试php,php7,pht,phtml等,都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接,得到flag...
设计模式和设计原则回顾
设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...

Opencv中的addweighted函数
一.addweighted函数作用 addweighted()是OpenCV库中用于图像处理的函数,主要功能是将两个输入图像(尺寸和类型相同)按照指定的权重进行加权叠加(图像融合),并添加一个标量值&#x…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序
一、开发准备 环境搭建: 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 项目创建: File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...
Robots.txt 文件
什么是robots.txt? robots.txt 是一个位于网站根目录下的文本文件(如:https://example.com/robots.txt),它用于指导网络爬虫(如搜索引擎的蜘蛛程序)如何抓取该网站的内容。这个文件遵循 Robots…...
是否存在路径(FIFOBB算法)
题目描述 一个具有 n 个顶点e条边的无向图,该图顶点的编号依次为0到n-1且不存在顶点与自身相连的边。请使用FIFOBB算法编写程序,确定是否存在从顶点 source到顶点 destination的路径。 输入 第一行两个整数,分别表示n 和 e 的值(1…...