python入门开发学习笔记之掌握Cpython的GIL解释器锁的工作机制

Python GIL锁 于是有了GIL这把超级大锁,而当越来越多的代码库开发者接受了这种设定后,他们开始大量依赖这种特性(即默认python内部对象是thread-safe的,无需在实现时考虑额外的内存锁和同步操作)。为了更有效的利用多核处理器的性能,就出现了多线程的编程方式,而随之带来的就是线程间数据一致性和状态同步的困难。所以虽然 CPython 的线程库直接封装操作系统的原生线程,但 CPython 进程做为一个整体,同一时间只会有一个获得了 GIL 的线程在跑,其它的线程都处于等待状态等着 GIL 的释放。 阅读详情

本节重点

  • 掌握Cpython的GIL解释器锁的工作机制
  • 掌握GIL与互斥锁
  • 掌握Cpython下多线程与多进程各自的应用场景

本节时长需控制在45分钟内

一 引子

定义:
In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple 
native threads from executing Python bytecodes at once. This lock is necessary mainly 
because CPython’s memory management is not thread-safe. (However, since the GIL 
exists, other features have grown to depend on the guarantees that it enforces.)

结论:在Cpython解释器中,同一个进程下开启的多线程,同一时刻只能有一个线程执行,无法利用多核优势

首先需要明确的一点是GIL并不是Python的特性,它是在实现Python解析器(CPython)时所引入的一个概念。就好比C++是一套语言(语法)标准,但是可以用不同的编译器来编译成可执行代码。>有名的编译器例如GCC,INTEL C++,Visual C++等。Python也一样,同样一段代码可以通过CPython,PyPy,Psyco等不同的Python执行环境来执行。像其中的JPython就没有GIL。然而因为CPython是大部分环境下默认的Python执行环境。所以在很多人的概念里CPython就是Python,也就想当然的把GIL归结为Python语言的缺陷。所以这里要先明确一点:GIL并不是Python的特性,Python完全可以不依赖于GIL

二 GIL介绍

GIL本质就是一把互斥锁,既然是互斥锁,所有互斥锁的本质都一样,都是将并发运行变成串行,以此来控制同一时间内共享数据只能被一个任务所修改,进而保证数据安全。

可以肯定的一点是:保护不同的数据的安全,就应该加不同的锁。

要想了解GIL,首先确定一点:每次执行python程序,都会产生一个独立的进程。例如python test.py,python aaa.py,python bbb.py会产生3个不同的python进程

验证python test.py只会产生一个进程

#test.py内容
import os,time
print(os.getpid())
time.sleep(1000)

#打开终端执行
python3 test.py

#在windows下查看
tasklist |findstr python

#在linux下下查看
ps aux |grep python

在一个python的进程内,不仅有test.py的主线程或者由该主线程开启的其他线程,还有解释器开启的垃圾回收等解释器级别的线程,总之,所有线程都运行在这一个进程内,毫无疑问

1、所有数据都是共享的,这其中,代码作为一种数据也是被所有线程共享的(test.py的所有代码以及Cpython解释器的所有代码)
例如:test.py定义一个函数work(代码内容如下图),在进程内所有线程都能访问到work的代码,于是我们可以开启三个线程然后target都指向该代码,能访问到意味着就是可以执行。

2、所有线程的任务,都需要将任务的代码当做参数传给解释器的代码去执行,即所有的线程要想运行自己的任务,首先需要解决的是能够访问到解释器的代码。

综上:

如果多个线程的target=work,那么执行流程是

多个线程先访问到解释器的代码,即拿到执行权限,然后将target的代码交给解释器的代码去执行

解释器的代码是所有线程共享的,所以垃圾回收线程也可能访问到解释器的代码而去执行,这就导致了一个问题:对于同一个数据100,可能线程1执行x=100的同时,而垃圾回收执行的是回收100的操作,解决这种问题没有什么高明的方法,就是加锁处理,如下图的GIL,保证python解释器同一时间只能执行一个任务的代码

三 GIL与Lock

机智的同学可能会问到这个问题:Python已经有一个GIL来保证同一时间只能有一个线程来执行了,为什么这里还需要lock?

首先,我们需要达成共识:锁的目的是为了保护共享的数据,同一时间只能有一个线程来修改共享的数据

然后,我们可以得出结论:保护不同的数据就应该加不同的锁。

最后,问题就很明朗了,GIL 与Lock是两把锁,保护的数据不一样,前者是解释器级别的(当然保护的就是解释器级别的数据,比如垃圾回收的数据),后者是保护用户自己开发的应用程序的数据,很明显GIL不负责这件事,只能用户自定义加锁处理,即Lock,如下图

分析:

1、100个线程去抢GIL锁,即抢执行权限
2、肯定有一个线程先抢到GIL(暂且称为线程1),然后开始执行,一旦执行就会拿到lock.acquire()
3、极有可能线程1还未运行完毕,就有另外一个线程2抢到GIL,然后开始运行,但线程2发现互斥锁lock还未被线程1释放,于是阻塞,被迫交出执行权限,即释放GIL
4、直到线程1重新抢到GIL,开始从上次暂停的位置继续执行,直到正常释放互斥锁lock,然后其他的线程再重复2 3 4的过程

代码示范

from threading import Thread,Lock
import os,time
def work():
    global n
    lock.acquire()
    temp=n
    time.sleep(0.1)
    n=temp-1
    lock.release()
if __name__ == '__main__':
    lock=Lock()
    n=100
    l=[]
    for i in range(100):
        p=Thread(target=work)
        l.append(p)
        p.start()
    for p in l:
        p.join()

    print(n) #结果肯定为0,由原来的并发执行变成串行,牺牲了执行效率保证了数据安全,不加锁则结果可能为99

四 GIL与多线程

有了GIL的存在,同一时刻同一进程中只有一个线程被执行

听到这里,有的同学立马质问:进程可以利用多核,但是开销大,而python的多线程开销小,但却无法利用多核优势,也就是说python没用了,php才是最牛逼的语言?

别着急啊,老娘还没讲完呢。

要解决这个问题,我们需要在几个点上达成一致:

1、cpu到底是用来做计算的,还是用来做I/O的?

2、多cpu,意味着可以有多个核并行完成计算,所以多核提升的是计算性能

3、每个cpu一旦遇到I/O阻塞,仍然需要等待,所以多核对I/O操作没什么用处

一个工人相当于cpu,此时计算相当于工人在干活,I/O阻塞相当于为工人干活提供所需原材料的过程,工人干活的过程中如果没有原材料了,则工人干活的过程需要停止,直到等待原材料的到来。

如果你的工厂干的大多数任务都要有准备原材料的过程(I/O密集型),那么你有再多的工人,意义也不大,还不如一个人,在等材料的过程中让工人去干别的活,

反过来讲,如果你的工厂原材料都齐全,那当然是工人越多,效率越高

结论:

1、对计算来说,cpu越多越好,但是对于I/O来说,再多的cpu也没用
2、当然对运行一个程序来说,随着cpu的增多执行效率肯定会有所提高(不管提高幅度多大,总会有所提高),这是因为一个程序基本上不会是纯计算或者纯I/O,所以我们只能相对的去看一个程序到底是计算密集型还是I/O密集型,从而进一步分析python的多线程到底有无用武之地

假设我们有四个任务需要处理,处理方式肯定是要玩出并发的效果,解决方案可以是:

方案一:开启四个进程
方案二:一个进程下,开启四个线程

单核情况下,分析结果:

如果四个任务是计算密集型,没有多核来并行计算,方案一徒增了创建进程的开销,方案二胜
如果四个任务是I/O密集型,方案一创建进程的开销大,且进程的切换速度远不如线程,方案二胜

多核情况下,分析结果:

如果四个任务是计算密集型,多核意味着并行计算,在python中一个进程中同一时刻只有一个线程执行用不上多核,方案一胜
如果四个任务是I/O密集型,再多的核也解决不了I/O问题,方案二胜

结论:

现在的计算机基本上都是多核,python对于计算密集型的任务开多线程的效率并不能带来多大性能上的提升,甚至不如串行(没有大量切换),但是,对于IO密集型的任务效率还是有显著提升的。

五 多线程性能测试

如果并发的多个任务是计算密集型:多进程效率高

from multiprocessing import Process
from threading import Thread
import os,time
def work():
    res=0
    for i in range(100000000):
        res*=i

if __name__ == '__main__':
    l=[]
    print(os.cpu_count()) #本机为4核
    start=time.time()
    for i in range(4):
        p=Process(target=work) #耗时5s多
        p=Thread(target=work) #耗时18s多
        l.append(p)
        p.start()
    for p in l:
        p.join()
    stop=time.time()
    print('run time is %s' %(stop-start))

如果并发的多个任务是I/O密集型:多线程效率高

from multiprocessing import Process
from threading import Thread
import threading
import os,time
def work():
    time.sleep(2)
    print('===>')

if __name__ == '__main__':
    l=[]
    print(os.cpu_count()) #本机为4核
    start=time.time()
    for i in range(400):
        # p=Process(target=work) #耗时12s多,大部分时间耗费在创建进程上
        p=Thread(target=work) #耗时2s多
        l.append(p)
        p.start()
    for p in l:
        p.join()
    stop=time.time()
    print('run time is %s' %(stop-start))

应用:

多线程用于IO密集型,如socket,爬虫,web
多进程用于计算密集型,如金融分析
讲一下Python的GIL。 全局解释器锁(GIL)是Python中最具争议也最常被误解的特性之一。作为CPython解释器的核心组件,GIL深刻影响着Python程序的并发性能和多线程行为。本文将带领读者进行一次GIL的深度探索之旅,从历史背景、工作原理到实际影响,全方位解析这一关键机制。我们将通过生动的比喻、详细的代码示例和可视化图表,揭开GIL的神秘面纱,帮助开发者真正理解它如何影响日常编程工作。 阅读详情

相关推荐

并发编程——线程——CPython的GIL解释器锁

一、GIL定义 In CPython, the global interpreter lock, or GIL, is a mutex that prevents multiple native threads from executing Python bytecodes at once. 在CPython中,全局解释器锁(global interpreter lock,GIL)是一个互斥锁,它...

Alex 611

python学习笔记 —— GIL

GIL GIL, 全局解释器锁[Global Interpreter Lock]是计算机程序设计语言解释器用于同步线程的一种机制. GIL保证同一时刻只有一个线程在一个CPU上运行字节码. GIL会根据执行的字节码行数和时间片释放GIL, GIL在遇到IO操作时会主动释放GIL GIL使得python等同于一个单线程程序. 下面是我找到的GIL的存在原因: 上图引用自: Python GIL全局解释器锁详解(深度剖析) ...

u011034683的博客 245

避坑指南:Livox Mid-360双雷达SLAM配置中,那些官方文档没说的细节(IP设置、话题分离与时间同步)

本文详细解析了Livox Mid-360双雷达SLAM配置中的关键优化点,包括IP设置、话题分离与时间同步等官方文档未提及的细节。通过实战案例和代码示例,帮助开发者解决点云错位、IMU数据混乱等问题,提升SLAM系统的稳定性和精度。特别针对网络架构设计、驱动修改和时间同步机制提供了专业指导。

weixin_29745609的博客 426

Python——GIL(全局解释器锁)

一、GIL   GIL的存在,不是Python语言自身的问题,而是因为CPython解释器引入的一个概念。CPython是Python的官方默认解释器,在CPython环境下使用多线程,就会出现GIL,它的作用是:保证在同一时间内,只能运行一个线程任务。 二、GIL与互斥锁 相同点: 都是为了解决线程间的资源抢夺、数据混乱的问题 不同点: 互斥锁是在Python代码层面上解决资源问题 GIL是在...

CodeSunShines 216

零成本实现飞牛 OS 内网穿透:CloudFlare 隧道搭建全攻略

一、引言:突破内网限制的最优解当你的内网环境中部署了飞牛 OS 系统(无论是老旧电脑还是 NAS 设备),想要实现公网访问时,传统方案往往面临两大痛点:公网 IP 申请困难且成本高DDNS 动态解析配置复杂专业内网穿透工具存在付费门槛今天为大家带来零成本解决方案:通过免费域名搭配 CloudFlare 隧道技术,无需公网 IP 即可轻松实现飞牛 OS 服务的公网访问。全程操作可视化,新手也能快速上手!二、前期准备:必备工具清单(1)域名准备。

Honmaple的博客 7493

【Unity】制作简易三维场景

本文介绍如何制作一个三维场景

CiNian_的博客 5333

python中的线程

单进程和单线程 程序在运行时可能有多个进程,每个进程中可能有多个线程,单cpu一次只能处理一个进程,采用分片处理让人们感觉是同时在运行。 多进程和多线程 一个物理cup可以分几核,也就可以理解为可以同时处理多个线程, 而且一个线程中的进程可以被不同的cpu处理(这种情况在python中不可能出现这种情况,因为python中有JIL,全局解释器锁,防止多个线程同时被执行,一次只能执行一个线程,

飞天喜欢你的博客 456

1.30 Cubemx_STM32H743 SD_Card纳入文件管理系统

Cubemx_STM32H743 SD_Card纳入文件管理系统1、简介2、CubeMX配置 1、简介 和前面文章原理其实一样的。 1.29 Cubemx_STM32F429\H743 nandflash、spifalsh纳入文件管理系统 现在一并将SD卡、NandFlash、SPIFlash一并作为文件管理。 下面直接介绍SDcard,其他参考前面文章。 2、CubeMX配置 ...

oDuanYanGuHong的博客 1080

GIL全局解释器锁

GIL介绍 GIL本质就是一把互斥锁,既然是互斥锁,所有互斥锁的本质都一样,都是将并发运行变成串行,以此来控制同一时间内共享数据只能被一个任务所修改,进而保证数据安全 如果多个线程的target=work,那么执行流程是: 多个线程先访问到解释器的代码,即拿到执行权限,然后将target的代码交给解释器的代码去执行 解释器的代码是所有线程共享的,所以垃圾回收线程也可能访问到解...

weixin_34290000的博客 124

CESM笔记——CESM1.0-CESM1.2.2-CESM2.1.3三个版本模式工作流对比

最近测试了CESM1.0,CESM1.2.2和CESM2.1.3三个版本,不同版本在workflow上有一些区别,来做点笔记。 CESM1.0 测试compset:B_2000,F_2000 workflow: 1. create_newcase -case ~/CESM/cesm1_0/script/B_2000 -compset B_2000 -res f19_g16 -mach tianhe 2. cd B_2000 (optional) env_mach_pes.xml ##修改核数,

砍柴姑娘Jourosy的博客 4944

GEE案例:Landsat 5、7、8影像构建1985-2023年rsei生态遥感指数详细代码

rsei(Regional Silviculture Ecological Index,地区林业生态指数)是一种生态遥感指标,用于评估森林生态系统的健康状况和生态服务。构建1985-2023年的rsei生态遥感指,主要需要使用Landsat 5、7和8的遥感影像数据。以下是一种可能的构建方法:1. 数据获取:从美国地质调查局(USGS)或其他可靠数据提供商处获取Landsat 5、7和8的遥感影像数据。确保选择的影像具有适当的空间和时间分辨率,以覆盖所需的时间段。

此星光明博客 3412

python的GIL锁

GIL锁

qq_45822672的博客 1635

【YOLOv8科研级优化】基于YOLOv9的GELAN模块重构C2f结构,实现精度与效率的同步提升

打开确保模型解析器能识别GELANBlock模块。通过将YOLOv9的GELAN模块集成到YOLOv8的C2f模块中,我们实现了一个“强特征表达+高效计算”的目标检测模型。这个改进不仅在工程上能提升复杂场景下的检测效果,更在科研上提供了“多分支特征融合”的创新思路——这种思路可以延伸到其他检测网络(如Faster R-CNN、SSD)的改进中,帮你在论文中打造独特的研究点。

know_F0727的博客 203

穿透 Python GIL 的迷雾:它到底锁的是什么?为什么 CPython 仍坚持多线程?

本文深入解析了Python的全局解释器锁(GIL)机制。GIL本质上是保护CPython解释器状态的全局锁,它确保引用计数和对象模型的线程安全,但只限制Python字节码执行,不影响I/O操作和C扩展。文章澄清了常见误解,指出GIL并不锁住所有线程或CPU核心。虽然GIL限制了CPU密集型任务的并行性,但多线程在I/O密集型任务中仍非常有效,且比多进程更轻量。文章还提供了绕过GIL的三种实践方案:多进程、C扩展和asyncio,并展望了Python未来可能支持的无GIL模式。

铭渊老黄 1553

k8s infiniband 和 RoCE(RDMA over Converged Ethernet)

vendors 为设备厂商编号,注意这里不是 ibv_devinfo 命令看到的vendor_id 的值,而是 lspci -n |grep “网卡的bdf” 得到的。如上文所述,启动了两个测试 pod ,登录其中一个 pod(该 pod roce 设备 ip 为 10.56.217.79)如上文所述,启动了两个测试 pod ,登录其中一个 pod(该 pod ip 为 10.96.225.24)说明:文中用到的镜像是自定义的,文末有其Dockerfile 文件。修改该文件,增加污点容忍的内容,如下。

weixin_40548182的博客 1796

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

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

GIL(Global Interpreter Lock)是CPython解释器中的一个互斥锁(mutex)机制,其核心作用是保护Python对象的访问,防止多个本地线程同时执行Python字节码。从技术实现角度来看,GIL确保在任一时刻只有一个线程能在Python解释器中执行代码。在实际运行过程中,假设程序创建了10个并发线程,在任一时刻检查CPU核心时,只能观察到一个线程在执行。每个线程在执行特定数量的字节码操作后,都会释放GIL并退出当前核心。

deephub 6890

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Python中的GIL锁

Python中的GIL锁 在Python中,可以通过多进程、多线程和多协程来实现多任务。 在多线程的实现过程中,为了避免出现资源竞争问题,可以使用互斥锁来使线程同步(按顺序)执行。 但是,其实Python的CPython(C语言实现的)解释器上有一把GIL锁,也就是说Python的程序是处于一个解释器锁的环境中的。 一、GIL介绍 GIL (Global Interperter Lock...

weixin_43790276的博客 5985

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

Python 解释器:CPython

CPython 是 Python 语言的官方解释器,由 C 语言编写,具备跨平台、稳定、生态丰富的特点。它将 Python 源代码编译为字节码,再由虚拟机逐条解释执行,是目前全球使用最广泛的 Python 实现。是官方的、最广泛使用的 Python 解释器。CPython 是 Python 官方维护的解释器,实现了 Python 语言规范,是其他解释器的“基准参考”。此外,CPython 的全局解释器锁(GIL)限制了多线程的并行性能,是其在并发计算中的一大瓶颈。

qq_41176800的博客 1831

Python解析器Cpython的GIL解释器锁工作机制

在Cpython解释器中,同一个进程下开启的多线程,同一时刻只能有一个线程执行,无法利用多核优势

Python966的博客 226

Python GIL(全局解释器锁)详解

Python GIL(全局解释器锁)详解, GIL

唐古的博客 1678

CPython的全局解释器锁-GIL即将成为历史

帧对象也不是线程安全的。最近,Cython 的维护者添加了对无 GIL 构建的支持,但你仍然需要确保你的代码是线程安全的。一般来说,任何在 Python 中使用的线程(而不是在外部,如扩展模块中使用的线程)都应该在 Python 中创建。无 GIL 的 Python 最大的障碍之一是确保用 C(或具有 C 兼容接口的语言)编写的 CPython 扩展能够尊重新的无 GIL 设计。举个例子,如果你有一个任务需要写入大量文件,如果每个任务都单独运行在一个线程中,效率会较低,因为写入文件本身是一个。

639

Python | GIL锁 | 5分钟掌握【全局解释器锁】(GIL)

GIL(Global Interpreter Lock)全局解释器锁;GIL (Global Interpreter Lock) 是 Python 部分解释器的一个重要特性。GIL 是一个全局锁,它限制了【一个进程】一次只能有【一个线程】在运行 Python 解释器中的字节码。即使你的程序有多个线程,在任意时刻,只有一个线程可以执行 Python 代码。

解决自己遇到的问题 分享认为有意义的知识 提供有一点点参考价值的灵感 2425

python gil锁_Cpython解释器中的GIL全局解释器锁

1、什么是GIL全局解释器锁GIL:Global Interpreter Lock,意思就是全局解释器锁,这个GIL并不是Python的特性,他是只在Cpython解释器里引入的一个概念,而在其他的语言编写的解释器里就没有GIL,例如:Jython,Pypy等下面是官方给出的解释:In CPython, the global interpreter lock, or GIL, is a mutex...

weixin_39747615的博客 136

浅谈Python GIL全局解释器锁

GIL的知识大多都是在面试的时候才会用到,但是抱着学习(或者说更好的与面试官扯皮)的心态,怎么也要了解的深入一些

qq_39915318的博客 3091

Python核心架构深度解析:从解释器原理到GIL机制全面剖析

本文系统梳理了 CPython 的核心运行机制:从源码→字节码→PVM 的完整执行链路,到统一对象模型、引用计数+分代回收的内存策略,再到 LEGB 作用域与 GIL 的权衡设计;结合 3.12 的 JIT 原型与 nogil 趋势,给出多进程、C 扩展、异步等性能规避方案,帮助开发者洞悉 Python 底层实现并写出高效代码。

需要远程指导仿真实验、代码有问题的,请后台私信。 1136

python之GIL锁

GIL全局解释器锁

qq_38039965的博客 930
上一篇: Python入门开发学习笔记之了解守护线程的概念
下一篇: python入门开发了解死锁现象与解决方法
程序员_大白
博客等级 码龄5年 1万+粉丝 4001原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值