首页 > 其他分享 >GIL锁、互斥锁

GIL锁、互斥锁

时间:2024-02-27 17:25:43浏览次数:18  
标签:解释器 多线程 Python lock 互斥 线程 GIL

一、GIL锁

1、全局解释器锁(Global Interpreter Lock,简称 GIL)

  GIL 是一种用于保护 Python 解释器在多线程环境下的数据完整性的机制。GIL 只存在是 CPython 解释器中,即官方的 Python 解释器实现

  GIL 是一个互斥锁,你可以使用多线程来并发处理任务,但在同一时刻只能有一个线程在执行 Python 字节码。

2、存在的背景

  GIL 的存在主要是因为 CPython 的内存管理机制(垃圾回收机制,python有一个垃回收线程)并不是线程安全的。

Python 中的对象引用计数机制(reference counting)是一种快速且高效的垃圾回收机制,但它对于多线程环境来说需要保证引用计数的一致性,这就需要 GIL 来确保同一时间只有一个线程能够访问和修改对象的引用计数。

由于 GIL 的存在,导致了 Python 在 CPU 密集型任务上的多线程性能并不理想。因为在这种情况下,即使使用了多个线程,由于 GIL 的限制,多个线程也不能真正并行执行,只能交替执行,因此无法充分利用多核 CPU 的优势。

然而,GIL 在 I/O 密集型任务上的影响较小。当线程执行 I/O 操作(如文件读写、网络请求)时,线程会主动释放 GIL,让其他线程有机会执行,从而提高了并发性能。

需要注意的是,GIL 只存在于 CPython 解释器中。其他一些 Python 解释器实现(如 Jython、IronPython)没有 GIL,它们可以更好地利用多线程并发执行。 

GIL 是 Python 解释器中的一种机制,用于保护解释器在多线程环境下的数据一致性。

虽然 GIL 限制了多线程的并行性能,但在 I/O 密集型任务中仍然可以提供一定的并发优势。

如果你需要在 Python 中处理 CPU 密集型任务,并发执行的需求较大,可以考虑使用多进程、异步编程或者使用其他 Python 解释器实现来绕过 GIL 的限制。

案例

创建了5个线程,每个线程都执行一个自增函数,该函数将一个全局计数器 counter 的值自增100万次。

由于 GIL 的限制,这段代码在多线程环境下并不能实现预期的并行效果。最终输出的计数器值通常会小于500万,而不是我们期望的500万(即每个线程自增100万次,共5个线程)。

这是因为 GIL 会确保在任何同一时间内只有一个线程在执行 Python 代码,导致多个线程无法同时访问和修改共享的计数器变量。没有抢到GIL锁的线程就会被释放掉。线程会交替地获取和释放 GIL,导致了部分线程的执行时间被浪费,没有执行。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 import threading import  time # 全局变量 counter = 0   # 自增函数 def increment():     global counter     for in range(1000000):         counter += 1   # 创建并启动多个线程 threads = [] for in range(5):     thread = threading.Thread(target=increment)     thread.start()     threads.append(thread)   # 等待所有线程执行完成 for thread in threads:     thread.join()   # 输出最终的计数器值 print("Final counter value:", counter) # Final counter value: 2301450

二、互斥锁(mutex)

1、互斥锁有进程锁和线程锁

互斥锁可以将并发变成串行,牺牲效率来保证数据的安全性。

线程锁(Lock)是基于线程的互斥量实现的,而进程锁(Lock)则是基于操作系统提供的进程间通信机制实现的。这意味着线程锁更加轻量级,适用于线程间的同步,而进程锁适用于不同进程之间的同步。

线程类中的锁和进程类中的锁在概念上是相似的,但在实现细节上可能有所不同,适用于不同的执行单位(线程或进程)。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 from multiprocessing  import  Process from multiprocessing  import Lock   def task(i, lock):     lock.acquire()     print('第%s个进程来了' % i)     print('第%s个进程走了' % i)     lock.release()   if __name__ == '__main__':     lock = Lock()     for in range(5):         = Process(target=task, args=(i, lock))  # 把锁当作位置参数传进去         p.start()

开启进程锁,当一个进程进来后,走了才能有下一个进程进来

互斥锁案例:买票

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 import json import time import random from multiprocessing import Lock, Process   #  查票 def check_ticket(i):     with open('a.txt''r') as f:         dic = json.load(f)     print('用户%s查询余票:%s' % (i, dic.get('ticket_num')))   # 买票 def buy(i):     with open('a.txt''r') as f:         dic = json.load(f)     # 模拟网络延迟     time.sleep(random.randint(13))     # 判断当前是否有票     if dic.get('ticket_num') > 0:         # 修改数据库,买票         dic['ticket_num'-= 1         # 写入数据库         with open('a.txt''w') as f1:             json.dump(dic, f1)             print('用户%s买票成功' % i)     else:         print('用户%s买票失败' % i)   def run(i, lock):     check_ticket(i)     # 买票环节加锁处理     lock.acquire()     buy(i)     lock.release()   if __name__ == '__main__':     # 在主进程生成锁     lock = Lock()       # 多进程     for in range(111):         = Process(target=run, args=(i, lock))         p.start()

注意:a.txt 中的数据是以json格式存在的 {"ticket_num": 1}

标签:解释器,多线程,Python,lock,互斥,线程,GIL
From: https://www.cnblogs.com/Jessica-Jmm/p/18037313

相关文章

  • python GIL 全局锁
    GIL由来我们先思考一个问题:我们在前面介绍的 list 、 dict 等内建对象是 线程安全 的吗?在 Python 层面,list 、dict 等内建对象是线程安全的,这是最基本的常识。研究 list、dict 等内建对象源码时,我们并没有看到任何 互斥锁 的痕迹,这多少有点令人意外。以 li......
  • Qt 设置button互斥,一组button只能选中一个
    一、同一容器内互斥效果1.先在界面是拖入一个控件容器,这里以QGroupBox为例2.再放进来几个按钮控件3.设置按钮属性,第一个红框勾选是设置按钮可选,第二个勾选就是设置自动互斥,当同一容器内的按钮勾选了这个选项就会自动互斥二、不同容器内互斥效果1.还是先设置所要互斥的......
  • 使用AgileConfig统一管理多项目配置
    使用AgileConfig统一管理多项目配置 背景一个设备的数字化管理软件系统,需要涵盖来料检验,部件装配,自动检验,装机激活,日常运营,维修保养,退役更换等生命周期流程,应用于生产车间,装机现场,客服运营等应用场景,业务复杂,角色众多,涉及的时间和空间范围都比较大,需要开发一系列的软件去解决......
  • 再测python3.13 —— python3.13是否移除了GIL的限制(续)
    前文:python3.13是否移除了GIL的限制x86_64ubuntu22.04环境下编译版本python3.13.0alpha0源码——python3.13.0alpha0的源码编译相关资料:PEP703–MakingtheGlobalInterpreterLockOptionalinCPythonhttps://github.com/python/cpython/issues/108223......
  • GIL全局解释器锁
    GIL全局解释器锁(1)简介在CPython中,GIL(全局解释器锁)是一种机制,用于确保在同一时刻只有一个线程执行Python字节码。这个锁对于Python解释器来说是必要的,因为CPython的内存管理并不是线程安全的。当多个线程试图执行Python代码时,GIL会确保同一时刻只有一个线程能够执行......
  • 【6.2】线程的互斥锁
    【一】问题所有子线程都会进行阻塞操作,导致最后的改变只是改了一次fromthreadingimportThreadimporttimemoney=100deftask():globalmoney#模拟获取到车票信息temp=money#模拟网络延迟time.sleep(2)#模拟购票money=......
  • 进程锁(互斥锁)
    进程锁(互斥锁)【一】什么是进程同步(互斥锁)互斥锁(Mutex)是一种用于多线程编程中控制对共享资源访问的机制。其作用是保证在同一时刻只有一个线程在访问共享资源,从而避免多个线程同时读写数据造成的问题。互斥锁的基本原理是在对共享资源进行访问前加锁,使得其他线程无法访问该......
  • linux之线程互斥(万字长文详解)
    linux之线程互斥多线程在访问共享资源时的问题假如我们设置一个全局变量!inttickets=1000;//充当有1000张票void*getTicket(void*args){std::stringusername=static_cast<constchar*>(args);while(true){if(tickets>0){......
  • 对GIL锁的理解
    对GIL锁的理解【1】介绍在Python中,GIL或全局解释器锁(GlobalInterpreterLock)是一个机制,用于限制Python解释器在多线程环境中同时执行多个线程的能力。这是Python核心解释器(CPython)中的一个重要部分,它的存在主要是为了简化CPython在内存管理上的操作,特别是为了避免与......
  • 线程同步之互斥锁
    目录如何使用Mutex中的lock与unlocktry_lock、try_lock_for和try_lock_untiltry_locktry_lock_fortry_lock_until如何使用Mutex中的lock与unlock在C++11中,您可以使用std::mutex中的lock和unlock函数来实现线程同步。lock函数用于锁定互斥量,而unlock函数用于解锁互斥量。下面是......