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 成为可选是什么看法呢?

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

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

相关文章

云卷云舒:kubernetes简介

Kubernetes是由google公司在2014年发布的一款开源的容器编排引擎,用于容器化应用程序的自动化部署、扩展与管理。它能够编排多种容器任务,涵盖虚拟机集群管理、负载均衡以及网络流量分配等等。2017年,aws、微软云、阿里云等等著名的云计算公司…

文献阅读1

A Hierarchical Representation Network for Accurate and Detailed Face Reconstruction from In-The-Wild Images 会议/期刊:CVPR 2023;阿里达摩院;Biwen Lei 概述:这是一篇单张图片三维人脸重建的论文,这篇论文的…

26、web攻防——通用漏洞SQL注入SqlmapOracleMongodbDB2

文章目录 OracleMongoDBsqlmap SQL注入课程体系; 数据库注入:access、mysql、mssql、oracle、mongodb、postgresql等数据类型注入:数字型、字符型、搜索型、加密型(base63 json)等提交方式注入:get、post、…

ChatGPT提示词大赏:GPT Prompts Hub 2024年最新ChatGPT提示词项目

🌟 GPT Prompts Hub 🌟 English | 简体中文 Security Prompts | GPTS Prompts 欢迎来到 “GPT Prompts Hub” 存储库!🌟 探索并分享高质量的 ChatGPT 提示词。培养创新性内容,提升对话体验,激发创造力。…

创建型模式 | 建造者模式

一、建造者模式 1、原理 建造者模式又叫生成器模式,是一种对象的构建模式。它可以将复杂对象的建造过程抽象出来,使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象。创建者模式是一步一步创建一个复杂的对象&#xf…

在App Store Connect上编辑多个用户的访问权限

作为一名编程新手,在App Store Connect中管理用户权限可能初听起来有些复杂,但实际上它是一个相对直接的过程。这里是一个步骤清晰的指南来帮助您在App Store Connect上编辑多个用户的访问权限。 App Store Connect 简介 在开始之前,让我们先…

Linux权限2

相关命令 chown [用户名] [文件]​ 更改文件拥有者(加sudo强制更改) chown [拥有者]:[所属组] [文件] 更改文件拥有者和所属组(root权限下) chgrp [用户名] [文件] 更改文件所属组 文件类型 输入ls或ll显示的文件&#xff…

网络协议攻击与模拟_02ARP协议

一、arp协议简介 一个工作在二层的三层协议,事一个2.5层协议 ARP协议地址解析协议,将一个已知的Ip地址解析为MAC地址,从而进行二层数据交互 二、工作流程 1、两个阶段 ARP请求ARP响应 两台主机IP地址主机A和主机B,IP地址和MAC…

Ubuntu 实时查看显存调用命令 free 及命令详解与原理说明(全)

Ubuntu 实时查看显存调用命令 free 及详解 文章目录 Ubuntu 实时查看显存调用命令 free 及详解1 free 作用1.1 语法:1.2 单独显示例子1.3 组合显示例子 2 输出介绍3 原理解释3.1 buff / cache(即 buffer / cache)3.1.1 buffer 缓冲区3.1.2 ca…

Java生成包含ehcarts报表的PDF文件,亲测有效!!!

1.引入maven依赖 <dependency><groupId>org.jfree</groupId><artifactId>jfreechart</artifactId><version>1.5.3</version></dependency><dependency><groupId>com.itextpdf</groupId><artifactId>i…

QT第三天

完善对话框&#xff0c;点击登录对话框&#xff0c;如果账号和密码匹配&#xff0c;则弹出信息对话框&#xff0c;给出提示”登录成功“&#xff0c;提供一个Ok按钮&#xff0c;用户点击Ok后&#xff0c;关闭登录界面&#xff0c;跳转到其他界面如果账号和密码不匹配&#xff0…

基于SELinux三权分立配置方法

1.系统安装 系统安装完成后,系统当前的SELinux配置为: # cat /etc/selinux/config SELINUX=enforcing SELINUXTYPE=targeted 2.SELinux环境准备 # yum install setools policycoreutils.x86_64 selinux-policy-mls.noarch setroubleshoot.x86_64 setools-console -y 3.SELin…

Qt/QML编程学习之心得:hicar手机投屏到车机中控的实现(32)

hicar,是华为推出的一款手机APP,有百度地图、华为音乐,更多应用中还有很多对应手机上装在的其他APP,都可以在这个里面打开使用,对开车的司机非常友好。但它不仅仅是用在手机上,它还可以投屏到车机中控上,这是比较神奇的一点。 HiCar本质上是一套智能投屏系统,理论上所有…

【Unity】Timer计时器属性及使用

可以代替协程完成延时操作 可以不用Update进行计时 GitHub开源计时插件 网址&#xff1a;https://github.com/akbiggs/UnityTimer/tree/master 导入&#xff1a;URL&#xff1a;https://github.com/akbiggs/UnityTimer.git 基本功能&#xff1a; 创建计时器&#xff1a; Time…

计算机导论03-计算机组成

计算机系统结构 冯•诺依曼体系结构 冯•诺依曼体系结构的基本要点 冯•诺依曼思想即冯•诺依曼体系结构思想&#xff0c;其最基本的概念是存储程序概念&#xff0c;它奠定了现代计算机的结构基础。 功能部件: 计算机必须具备五大基本组成部件&#xff0c;包括&#xff1a;运…

15个等轴视图设计的电动车汽车无人机等PR剪辑素材视频制作元素

包含15个等轴视图、等距视角电动车、汽车、无人机、沙漏、飞机等PR剪辑素材视频制作元素mogrt动画模板。 特征&#xff1a; 等距设计&#xff1b; 可以更改颜色&#xff1b; 分辨率&#xff1a;全高清&#xff08;19201080&#xff09;&#xff1b; 持续时间&#xff1a;15秒&a…

[机缘参悟-122] :IT人如何认识自己的?自省、面试、考核、咨询?

目录 一、为什么要认识自己 二、认识自己的哪些方面&#xff1f; 三、如何认识自己 3.1 通过自省认识自己 3.2 通过面试认识自己 3.3 通过咨询认识自己 3.4 通过相亲认识自己 3.5 通过一段感情关系认识自己 一、为什么要认识自己 认识自己在人类的成长和心灵发展过程中…

RTX20系开启超分辨率

我的显卡是2070s现在也支持了超分辨率,根据网上的教程一通折腾后发现了不少的坑,记一下.希望有缘人可以少走点弯路. 机器配置如下: [CPU] CPU #1: 3600MHz, AMD Ryzen 7 3700X 8-Core Processor , AMD64 Family 23 Model 113 Stepping Instruction set: MMX MMX…

Camunda外部任务

外部任务&#xff1a;即任务可以在外部系统进行审批。 一&#xff1a;pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instan…

零基础学习数学建模——(二)数学建模的步骤

本篇博客将详细介绍数学建模的步骤。 文章目录 引例&#xff1a;年夜饭的准备第一步&#xff1a;模型准备第二步&#xff1a;模型假设第三步&#xff1a;模型建立第四步&#xff1a;模型求解第五步&#xff1a;结果分析第六步&#xff1a;模型检验第七步&#xff1a;模型应用及…