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()
    
    

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

    mutex_lock.acquire()
    
  3. 访问共享资源: 在互斥锁的保护下,对共享资源进行读取或修改操作。

  4. 释放锁(解锁): 在访问共享资源完成后,使用 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模块更为合适。

你可能感兴趣的:(并发编程,python,java,开发语言)