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

本文涉及的产品
智能开放搜索 OpenSearch行业算法版,1GB 20LCU 1个月
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
实时数仓Hologres,5000CU*H 100GB 3个月
简介: 在Python开发中,GIL(全局解释器锁)一直备受关注。本文基于CPython解释器,探讨GIL的技术本质及其对程序性能的影响。GIL确保同一时刻只有一个线程执行代码,以保护内存管理的安全性,但也限制了多线程并行计算的效率。文章分析了GIL的必要性、局限性,并介绍了多进程、异步编程等替代方案。尽管Python 3.13计划移除GIL,但该特性至少要到2028年才会默认禁用,因此理解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

目录
相关文章
|
25天前
|
供应链 监控 安全
对话|企业如何构建更完善的容器供应链安全防护体系
阿里云与企业共筑容器供应链安全
171357 14
|
27天前
|
供应链 监控 安全
对话|企业如何构建更完善的容器供应链安全防护体系
随着云计算和DevOps的兴起,容器技术和自动化在软件开发中扮演着愈发重要的角色,但也带来了新的安全挑战。阿里云针对这些挑战,组织了一场关于云上安全的深度访谈,邀请了内部专家穆寰、匡大虎和黄竹刚,深入探讨了容器安全与软件供应链安全的关系,分析了当前的安全隐患及应对策略,并介绍了阿里云提供的安全解决方案,包括容器镜像服务ACR、容器服务ACK、网格服务ASM等,旨在帮助企业构建涵盖整个软件开发生命周期的安全防护体系。通过加强基础设施安全性、技术创新以及倡导协同安全理念,阿里云致力于与客户共同建设更加安全可靠的软件供应链环境。
150300 32
|
1月前
|
弹性计算 人工智能 安全
对话 | ECS如何构筑企业上云的第一道安全防线
随着中小企业加速上云,数据泄露、网络攻击等安全威胁日益严重。阿里云推出深度访谈栏目,汇聚产品技术专家,探讨云上安全问题及应对策略。首期节目聚焦ECS安全性,提出三道防线:数据安全、网络安全和身份认证与权限管理,确保用户在云端的数据主权和业务稳定。此外,阿里云还推出了“ECS 99套餐”,以高性价比提供全面的安全保障,帮助中小企业安全上云。
201980 15
对话 | ECS如何构筑企业上云的第一道安全防线
|
2天前
|
Linux iOS开发 MacOS
deepseek部署的详细步骤和方法,基于Ollama获取顶级推理能力!
DeepSeek基于Ollama部署教程,助你免费获取顶级推理能力。首先访问ollama.com下载并安装适用于macOS、Linux或Windows的Ollama版本。运行Ollama后,在官网搜索“deepseek”,选择适合你电脑配置的模型大小(如1.5b、7b等)。通过终端命令(如ollama run deepseek-r1:1.5b)启动模型,等待下载完成即可开始使用。退出模型时输入/bye。详细步骤如下图所示,轻松打造你的最强大脑。
1080 68
|
9天前
|
机器学习/深度学习 自然语言处理
Deepseek开源R1系列模型,纯RL助力推理能力大跃升!
近期Deepseek正式发布 DeepSeek-R1,并同步开源模型权重。DeepSeek-R1 遵循 MIT License,允许用户通过蒸馏技术借助 R1 训练其他模型。
|
4天前
|
人工智能 JavaScript 前端开发
白嫖 DeepSeek ,低代码竟然会一键作诗?
宜搭低代码平台接入 DeepSeek AI 大模型能力竟然这么方便!本教程将揭秘宜搭如何快速接入 DeepSeek API,3 步打造专属作诗机器人,也许你还能开发出更多有意思的智能玩法,让创意在代码间自由生长。
610 11
|
2天前
|
Linux iOS开发 MacOS
DeepSeek爆火,如何免费部署到你的电脑上?获取顶级推理能力教程来了
如何在本地电脑上免费部署DeepSeek,获取顶级推理能力?只需三步:1. 访问Ollama官网下载并安装对应操作系统的版本(支持macOS、Linux和Windows)。2. 打开Ollama并确保其正常运行。3. 在Ollama官网搜索并选择DeepSeek模型(如deepseek-r1),根据电脑配置选择合适的模型大小(1.5B至671B)。通过终端命令(如ollama run deepseek-r1:1.5b)运行模型,即可开始使用DeepSeek进行推理。退出模型时,在终端输入/bye。更多详情请参考Ollama官方文档。
|
13天前
|
机器学习/深度学习 自然语言处理 PyTorch
深入剖析Transformer架构中的多头注意力机制
多头注意力机制(Multi-Head Attention)是Transformer模型中的核心组件,通过并行运行多个独立的注意力机制,捕捉输入序列中不同子空间的语义关联。每个“头”独立处理Query、Key和Value矩阵,经过缩放点积注意力运算后,所有头的输出被拼接并通过线性层融合,最终生成更全面的表示。多头注意力不仅增强了模型对复杂依赖关系的理解,还在自然语言处理任务如机器翻译和阅读理解中表现出色。通过多头自注意力机制,模型在同一序列内部进行多角度的注意力计算,进一步提升了表达能力和泛化性能。
|
17天前
|
存储 人工智能 安全
对话|无影如何助力企业构建办公安全防护体系
阿里云无影助力企业构建办公安全防护体系
1262 11
|
3天前
|
机器学习/深度学习 搜索推荐 PyTorch
基于昇腾用PyTorch实现传统CTR模型WideDeep网络
本文介绍了如何在昇腾平台上使用PyTorch实现经典的WideDeep网络模型,以处理推荐系统中的点击率(CTR)预测问题。
148 65