Python GIL(全局解释器锁)机制对多线程性能影响的深度分析

在Python开发领域,GIL(Global Interpreter Lock)一直是一个广受关注的技术话题。在3.13已经默认将GIL去除,在详细介绍3.13的更亲前,我们先要留了解GIL的技术本质、其对Python程序性能的影响。本文将主要基于CPython(用C语言实现的Python解释器,也是目前应用最广泛的Python解释器)展开讨论。

GIL的技术定义

GIL(Global Interpreter Lock)是CPython解释器中的一个互斥锁(mutex)机制,其核心作用是保护Python对象的访问,防止多个本地线程同时执行Python字节码。从技术实现角度来看,GIL确保在任一时刻只有一个线程能在Python解释器中执行代码。

在实际运行过程中,假设程序创建了10个并发线程,在任一时刻检查CPU核心时,只能观察到一个线程在执行。每个线程在执行特定数量的字节码操作后,都会释放GIL并退出当前核心。在CPython的默认实现中,每个线程可以在释放GIL之前执行100个字节码指令。GIL释放后,其他等待线程中的一个将获得锁并开始执行。

从实现机制来看,GIL可以被视为一个线程执行令牌,线程必须获取这个令牌才能执行字节码指令。

GIL的技术必要性

GIL的存在与CPython的内存管理机制密切相关。要理解GIL的必要性,需要先了解CPython的内存管理实现原理。

CPython采用引用计数(reference counting)作为其主要的内存管理机制。系统会为每个Python对象维护一个引用计数器,记录指向该对象的引用数量。当引用计数降至零时,对象占用的内存将被立即释放。

在多线程环境下对同一Python对象的访问在多线程场景下,考虑如下情况:假设有3个线程同时持有对同一Python对象的引用,此时该对象的引用计数为3。当一个线程释放对该对象的引用时,计数值降为2。

这里存在一个关键的技术问题:如果两个线程同时释放对该对象的引用,会出现竞争条件(race condition)。在这种情况下,引用计数可能只会减少一次而不是预期的两次,导致最终引用计数为2而不是1。这将导致对象永远保持非零引用计数,使得垃圾回收器无法回收该对象,最终造成内存泄漏。

GIL的设计正是为了解决这个问题。通过确保同一时刻只有一个线程在执行,GIL有效防止了多线程环境下的引用计数竞争问题。这种机制保证了对Python对象的访问是串行的,从而维护了解释器内部状态的一致性。

GIL的技术局限性

GIL虽然解决了内存管理的并发问题,但同时也带来了性能方面的技术挑战。

最主要的性能开销来自于线程执行时频繁的GIL获取和释放操作。这种额外的同步开销导致了多线程程序在某些场景下的性能反而低于单线程程序。

以下是具体的性能测试示例。首先是单线程实现:

 importtime  defmyfunc():  """  执行5亿次迭代的高精度计时测试"""  before_time=time.perf_counter()  for_inrange(500000000):  pass  after_time=time.perf_counter()  elapsed_time=after_time-before_time  print(f"Time taken in total: {elapsed_time:.6f} seconds")  if__name__=="__main__":  myfunc()

单线程执行结果显示耗时约8.426秒

对比使用两个线程的实现:

 importtime  importthreading  defworker(iterations, thread_id):  """  执行指定迭代次数的工作线程函数参数: iterations (int): 迭代执行次数thread_id (int): 线程标识号"""  print(f"Thread {thread_id} starting.")  for_inrange(iterations):  pass  print(f"Thread {thread_id} finished.")  defmyfunc():  """  将5亿次迭代平均分配给两个线程执行的性能测试"""  total_iterations=500000000  half_iterations=total_iterations//2  thread1=threading.Thread(target=worker, args=(half_iterations, 1))  thread2=threading.Thread(target=worker, args=(half_iterations, 2))  print("Starting threads...")  before_time=time.perf_counter()  thread1.start()  thread2.start()  thread1.join()  thread2.join()  after_time=time.perf_counter()  elapsed_time=after_time-before_time  print(f"Time taken in total: {elapsed_time:.6f} seconds")  if__name__=="__main__":  myfunc()

多线程执行结果显示耗时约11.256秒

这个性能测试清晰地展示了GIL对Python多线程执行效率的影响,同时也说明了Python在实现真正的线程级并行计算时所面临的技术限制。

3.13 前的技术解决方案

针对GIL带来的限制,目前有多种技术解决方案,但每种方案都有其特定的应用场景和局限性:

多进程方案: 通过Python的

multiprocessing

模块,可以创建多个独立的Python解释器进程,每个进程都拥有独立的GIL和内存空间,从而实现真正的并行计算。

异步编程: 对于I/O密集型应用,可以使用异步编程模型(如asyncio)实现并发,这种方式可以在单线程环境下高效处理并发任务,降低GIL的影响。

替代性Python实现: 一些Python的其他实现(如Jython、IronPython、PyPy)采用了不同的内存管理机制,不依赖GIL。这些实现通过不同的技术方案避免了GIL的限制,但可能会带来其他方面的权衡。

总结

GIL是CPython实现中的一个核心设计决策,它在保证内存管理安全性的同时也带来了并行计算效率的限制。在实际开发中,需要根据具体的应用场景选择合适的技术方案来规避或降低GIL的影响。理解GIL的技术本质和局限性,对于设计高性能的Python应用系统具有重要意义。

PEP 703 提出的移除 GIL 的设计,不仅解决了 GIL 带来的多线程性能瓶颈,还通过细粒度锁、乐观锁、RCU 和 STW 等多种机制,在性能和线程安全之间实现了巧妙的平衡。但是根据 Python 路线图显示,至少要到 2028 年,GIL 才会被默认禁用。所以目前来看的话了解GIL还是十分有必要的。

https://avoid.overfit.cn/post/3545a1aabf5a4452861804a1c5340ac0

作者:Sambhu Nampoothiri G

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Git 版本控制:基础介绍与常用操作

目录 Git 的基本概念 Git 安装与配置 Git 常用命令与操作 1. 初始化本地仓库 2. 版本控制工作流程 3. 分支管理 4. 解决冲突 5. 回退和撤销 6. 查看提交日志 前言 在软件开发过程中,开发者常常需要在现有程序的基础上进行修改和扩展。但如果不加以管理&am…

(笔记+作业)书生大模型实战营春节卷王班---L0G2000 Python 基础知识

学员闯关手册:https://aicarrier.feishu.cn/wiki/QtJnweAW1iFl8LkoMKGcsUS9nld 课程视频:https://www.bilibili.com/video/BV13U1VYmEUr/ 课程文档:https://github.com/InternLM/Tutorial/tree/camp4/docs/L0/Python 关卡作业:htt…

仿真设计|基于51单片机的高速路口货车称重系统仿真

目录 具体实现功能 设计介绍 51单片机简介 资料内容 仿真实现(protues8.7) 程序(Keil5) 全部内容 资料获取 具体实现功能 (1)LCD1602液晶第一行显示当前的车辆重量,第二行显示车辆重量…

Ubuntu Server 安装 XFCE4桌面

Ubuntu Server没有桌面环境,一些软件有桌面环境使用起来才更加方便,所以我尝试安装桌面环境。常用的桌面环境有:GNOME、KDE Plasma、XFCE4等。这里我选择安装XFCE4桌面环境,主要因为它是一个极轻量级的桌面环境,适合内…

2025:影刀RPA使用新实践--CSDN博客下载

文章目录 一键CSDN博客下载器程序说明指导说明使用步骤 获取方法 一键CSDN博客下载器 程序说明 配置信息:CSDN账号(手机号/邮箱/用户名)、密码、博客文件类型支持markdown格式、html格式(默认值markdown格式)、博客保…

深度学习的应用

目录 一、机器视觉 1.1 应用场景 1.2 常见的计算机视觉任务 1.2.1 图像分类 1.2.2 目标检测 1.2.3 图像分割 二、自然语言处理 三、推荐系统 3.1 常用的推荐系统算法实现方案 四、图像分类实验补充 4.1 CIFAR-100 数据集实验 实验代码 4.2 CIFAR-10 实验代码 深…

前端js高级25.1.30

原型:函数的组成结构 通过这个图我们需要知道。 假设我们创建了一个Foo函数。 规则:Function.protoType是函数显示原型。__proto__是隐式对象。 Function、Object、Foo函数的__proto__指向了Function.protoType说明。这三个都依托function函数来创建。…

为AI聊天工具添加一个知识系统 之80 详细设计之21 符号逻辑 之1

本文要点 要点 前面我们讨论了本项目中的正则表达式。现在我们将前面讨论的正则表达式视为狭义的符号文本及其符号规则rule(认识的原则--认识上认识对象的约束),进而在更广泛的视角下将其视为符号逻辑及其符号原则principle(知识…

.NET Core缓存

目录 缓存的概念 客户端响应缓存 cache-control 服务器端响应缓存 内存缓存(In-memory cache) 用法 GetOrCreateAsync 缓存过期时间策略 缓存的过期时间 解决方法: 两种过期时间策略: 绝对过期时间 滑动过期时间 两…

自动驾驶---苏箐对智驾产品的思考

1 前言 对于更高级别的自动驾驶,很多人都有不同的思考,方案也好,产品也罢。最近在圈内一位知名的自动驾驶专家苏箐发表了他自己对于自动驾驶未来的思考。 苏箐是地平线的副总裁兼首席架构师,同时也是高阶智能驾驶解决方案SuperDri…

Sklearn 中的逻辑回归

逻辑回归的数学模型 基本模型 逻辑回归主要用于处理二分类问题。二分类问题对于模型的输出包含 0 和 1,是一个不连续的值。分类问题的结果一般不能由线性函数求出。这里就需要一个特别的函数来求解,这里引入一个新的函数 Sigmoid 函数,也成…

FPGA|使用quartus II通过AS下载POF固件

1、将开发板设置到AS下载挡位,或者把下载线插入到AS端口 2、打开quartus II,选择Tools→Programmer→ Mode选择Active Serial Programming 3、点击左侧Add file…,选择 .pof 文件 →start 4、勾选program和verify(可选&#xff0…

浅谈网络 | 容器网络之Flannel

目录 云原生网络架构深度解构:Flannel的设计哲学与实现机制Flannel架构解析:三层核心设计原则UDP模式(用户态隧道)VXLAN模式(内核态隧道)Host-GW模式(直连路由) 生产环境架构选型与调…

hive:基本数据类型,关于表和列语法

基本数据类型 Hive 的数据类型分为基本数据类型和复杂数据类型 加粗的是常用数据类型 BOOLEAN出现ture和false外的其他值会变成NULL值 没有number,decimal类似number 如果输入的数据不符合数据类型, 映射时会变成NULL, 但是数据本身并没有被修改 创建表 创建表的本质其实就是在…

2025创业思路和方向有哪些?

创业思路和方向是决定创业成功与否的关键因素。以下是一些基于找到的参考内容的创业思路和方向,旨在激发创业灵感: 一、技术创新与融合: 1、智能手机与云电视结合:开发集成智能手机功能的云电视,提供通讯、娱乐一体化体…

Three.js实战项目02:vue3+three.js实现汽车展厅项目

文章目录 实战项目02项目预览项目创建初始化项目模型加载与展厅灯光加载汽车模型设置灯光材质设置完整项目下载实战项目02 项目预览 完整项目效果: 项目创建 创建项目: pnpm create vue安装包: pnpm add three@0.153.0 pnpm add gsap初始化项目 修改App.js代码&#x…

年化19.3%策略集|ctpbee_api替换成openctp整合backtrader实盘方案(代码+数据)

原创内容第782篇,专注量化投资、个人成长与财富自由。 昨天我们把backtraderctpbee的实盘整合代码跑通了,年化19.3%,回撤仅8%的实盘策略,以及backtrader整合CTPBee做实盘(附python代码和数据) 这两周我们加…

Android Studio 正式版 10 周年回顾,承载 Androider 的峥嵘十年

Android Studio 1.0 宣发于 2014 年 12 月,而现在时间来到 2025 ,不知不觉间 Android Studio 已经陪伴 Androider 走过十年历程。 Android Studio 10 周年,也代表着了我的职业生涯也超十年,现在回想起来依然觉得「唏嘘」&#xff…

OpenEuler学习笔记(十四):在OpenEuler上搭建.NET运行环境

一、在OpenEuler上搭建.NET运行环境 基于包管理器安装 添加Microsoft软件源:运行命令sudo rpm -Uvh https://packages.microsoft.com/config/centos/8/packages-microsoft-prod.rpm,将Microsoft软件源添加到系统中,以便后续能够从该源安装.…

Vscode编辑器下 Markdown无法显示图片

1.问题 在vscode 编辑器中无法预览 markdon 文件中的图片 2.解决方案 大部分出现这种情况是因为新版本的vscode会阻拦有风险的资源显示,将安全等级调低即可。 方式一: 1.打开任意 MD 文件,ctrl,调出设置 2. 输入 markdown.ch…