GIL锁,互斥锁

发布时间 2023-07-07 15:43:13作者: 凡人半睁眼

一、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,导致了部分线程的执行时间被浪费,没有执行。

import threading
import  time
# 全局变量
counter = 0

# 自增函数
def increment():
    global counter
    for i in range(1000000):
        counter += 1

# 创建并启动多个线程
threads = []
for i 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

二、互斥锁

1、