Python全局解释器锁(Global Interpreter Lock,简称 GIL), 互斥锁

简介: Python全局解释器锁(Global Interpreter Lock,简称 GIL), 互斥锁

一.全局解释器锁(Global Interpreter Lock,简称 GIL)

全局解释器锁(Global Interpreter Lock,简称 GIL)是在 CPython 解释器中的一种机制。CPython 是 Python 的官方解释器,它使用 GIL 来确保在任何时刻只有一个线程执行 Python 字节码。

GIL 的存在主要是为了简化 CPython 解释器的实现,使得它能更容易地处理并发情况。然而,GIL 也引入了一些限制,特别是在多核处理器上的并行执行方面。

主要特点和影响:

  1. 单线程执行: 在任何给定的时刻,只有一个线程能够执行 Python 字节码。即使在多核处理器上运行 Python 程序,由于 GIL 的存在,同一时刻只有一个核心在执行 Python 代码。
  2. 对多线程性能的影响: GIL 对于 CPU 密集型任务(计算密集型任务)的性能影响较大,因为它阻止了多个线程的并行执行。然而,在 I/O 密集型任务(例如网络请求、文件读写)中,GIL 的影响较小,因为线程在等待外部资源时可以释放 GIL。
  3. 影响多进程编程: 多进程编程可以在多核系统上实现真正的并行执行,因为每个进程都有自己的 Python 解释器和 GIL。在多进程模型中,每个进程都可以独立运行,不受 GIL 的限制。
  4. Python 中的内存管理: GIL 对于 Python 中的内存管理有一些影响。由于 GIL 的存在,CPython 在处理内存分配和垃圾回收时需要额外的考虑,以确保线程安全。

需要注意的是,GIL 是 CPython 解释器的特性,其他一些 Python 解释器(例如 Jython、IronPython)并不具备 GIL。如果你的应用对并发性能有较高的要求,你可以考虑使用多进程、使用其他解释器,或者使用其他并发编程模型(如异步编程)。

二. 互斥锁

1. 定义

互斥锁(Mutex Lock)是一种同步原语,用于在多线程或多进程环境中控制对共享资源的访问。在 Python 中,你可以使用 threading 模块(用于线程)或 multiprocessing 模块(用于进程)提供的 Lock 类来实现互斥锁。

互斥锁的主要目的是确保在任何时刻只有一个线程(或进程)能够访问共享资源,以防止数据竞态和不一致的状态。在并发编程中,多个线程或进程可能同时访问和修改共享的数据,而互斥锁能够帮助你控制这种访问,确保数据的一致性。

2. 在 Python 中,使用互斥锁通常涉及以下步骤:

  1. 创建互斥锁对象: 使用 threading.Lock()multiprocessing.Lock() 创建一个互斥锁对象。

import threading


# 创建互斥锁

mutex_lock = threading.Lock()



  1. 获取锁(加锁): 在访问共享资源之前,使用 lock.acquire() 获取互斥锁。如果锁已经被其他线程或进程持有,则当前线程(或进程)将被阻塞,直到锁被释放。

mutex_lock.acquire()


  1. 访问共享资源: 在互斥锁的保护下,对共享资源进行读取或修改操作。
  2. 释放锁(解锁): 在访问共享资源完成后,使用 lock.release() 释放互斥锁,以允许其他线程或进程获取锁并访问共享资源。

mutex_lock.release()


3.以下是一个简单的示例,演示了如何使用互斥锁来保护共享资源:

 

import threading
 
# 共享资源
shared_variable = 0
 
# 创建互斥锁
mutex_lock = threading.Lock()
 
def worker():
    global shared_variable
    for _ in range(100000):
        # 获取互斥锁
        mutex_lock.acquire()
        shared_variable += 1
        # 释放互斥锁
        mutex_lock.release()
 
# 创建多个线程
threads = []
for _ in range(5):
    thread = threading.Thread(target=worker)
    threads.append(thread)
    thread.start()
 
# 等待所有线程结束
for thread in threads:
    thread.join()
 
print(f"Final value of shared_variable: {shared_variable}")

       

在这个例子中,多个线程同时对 shared_variable 进行累加操作,通过互斥锁确保了对共享资源的访问是线程安全的。最终输出的 shared_variable 的值应该是 5 * 100000 = 500000

4.互斥锁使用进阶

import multiprocessing
 
def worker(lock, shared_variable):
    for _ in range(5):
        with lock:
            shared_variable.value += 1
            print(f"Process {multiprocessing.current_process().name}: {shared_variable.value}")
            
if __name__ == "__main__":
    # 创建共享变量和互斥锁
    shared_variable = multiprocessing.Value("i", 0)
    lock = multiprocessing.Lock()
 
    # 创建多个进程,每个进程都调用worker函数
    processes = []
    for i in range(3):
        process = multiprocessing.Process(target=worker, args=(lock, shared_variable))
        processes.append(process)
        process.start()
 
    # 等待所有进程结束
    for process in processes:
        process.join()

在上面的例子中,我们使用了multiprocessing.Value创建一个共享的整数变量shared_variable,并使用multiprocessing.Lock创建一个互斥锁lock。在worker函数中,我们使用with lock语句来确保对共享变量的访问是互斥的,以防止多个进程同时修改它。

需要注意的是,这里使用了multiprocessing.Value来创建共享变量,而不是简单的整数。这是因为multiprocessing模块中的数据类型在多个进程之间共享时更安全。在这个例子中,我们使用了整数类型("i"表示整数),但你可以根据需要选择其他类型。

请注意,这里使用的是multiprocessing模块而不是threading模块,因为threading模块在CPython解释器中由于全局解释器锁(GIL)的存在,不能真正实现多核并行。如果你的应用程序需要充分利用多核处理器,使用multiprocessing模块更为合适。

相关文章
|
3月前
|
数据采集 存储 安全
如何确保Python Queue的线程和进程安全性:使用锁的技巧
本文探讨了在Python爬虫技术中使用锁来保障Queue(队列)的线程和进程安全性。通过分析`queue.Queue`及`multiprocessing.Queue`的基本线程与进程安全特性,文章指出在特定场景下使用锁的重要性。文中还提供了一个综合示例,该示例利用亿牛云爬虫代理服务、多线程技术和锁机制,实现了高效且安全的网页数据采集流程。示例涵盖了代理IP、User-Agent和Cookie的设置,以及如何使用BeautifulSoup解析HTML内容并将其保存为文档。通过这种方式,不仅提高了数据采集效率,还有效避免了并发环境下的数据竞争问题。
如何确保Python Queue的线程和进程安全性:使用锁的技巧
|
1月前
|
Java C语言 Python
解析Python中的全局解释器锁(GIL):影响、工作原理及解决方案
解析Python中的全局解释器锁(GIL):影响、工作原理及解决方案
46 0
|
2月前
|
存储 算法 Java
关于python3的一些理解(装饰器、垃圾回收、进程线程协程、全局解释器锁等)
该文章深入探讨了Python3中的多个重要概念,包括装饰器的工作原理、垃圾回收机制、进程与线程的区别及全局解释器锁(GIL)的影响等,并提供了详细的解释与示例代码。
29 0
|
3月前
|
数据采集 Java Python
python 递归锁、信号量、事件、线程队列、进程池和线程池、回调函数、定时器
python 递归锁、信号量、事件、线程队列、进程池和线程池、回调函数、定时器
|
3月前
|
消息中间件 存储 安全
python多进程并发编程之互斥锁与进程间的通信
python多进程并发编程之互斥锁与进程间的通信
|
6月前
|
并行计算 Python
python并发编程: Python速度慢的罪魁祸首,全局解释器锁GIL
python并发编程: Python速度慢的罪魁祸首,全局解释器锁GIL
60 1
python并发编程: Python速度慢的罪魁祸首,全局解释器锁GIL
|
机器学习/深度学习 人工智能 安全
Python社区变天:可去除全局解释器锁GIL,真正多线程要来了
Python社区变天:可去除全局解释器锁GIL,真正多线程要来了
369 0
|
存储 开发框架 缓存
Python 新提案:“废除”全局解释器锁 GIL | CPython 解释器或许会变得更快
Python 新提案:“废除”全局解释器锁 GIL | CPython 解释器或许会变得更快
281 0
Python 新提案:“废除”全局解释器锁 GIL | CPython 解释器或许会变得更快
|
测试技术 调度 C++
Python的全局解释器锁(GIL)
转一篇关于Python GIL的文章。 归纳一下,CPU的大规模电路设计基本已经到了物理意义的尽头,所有厂商们都开始转向多核以进一步提高性能。Python为了能利用多核多线程的的优势,但又要保证线程之间数据完整性和状态同步,就采用了最简单的加锁的方式(所以说Python的GIL是设计之初一时偷懒造成的!)。
2358 0
|
7天前
|
机器学习/深度学习 人工智能 TensorFlow
人工智能浪潮下的自我修养:从Python编程入门到深度学习实践
【10月更文挑战第39天】本文旨在为初学者提供一条清晰的道路,从Python基础语法的掌握到深度学习领域的探索。我们将通过简明扼要的语言和实际代码示例,引导读者逐步构建起对人工智能技术的理解和应用能力。文章不仅涵盖Python编程的基础,还将深入探讨深度学习的核心概念、工具和实战技巧,帮助读者在AI的浪潮中找到自己的位置。