# Python 全局解释器锁 (GIL) 详细解析

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

什么是 GIL?

全局解释器锁(Global Interpreter Lock,简称 GIL)是 Python 解释器(主要是 CPython)中的一个互斥锁,它确保在任何时刻只有一个线程能够执行
Python 字节码。这个机制存在于 CPython 解释器中,但并不存在于 Jython、IronPython 或 PyPy-STM 等其他 Python 实现中。

GIL 的工作原理

GIL 的核心机制如下:

  1. 单线程执行:即使在多核处理器上,CPython 解释器也只允许一个线程执行 Python 字节码
  2. 线程切换:Python 线程在执行一定数量的字节码指令或遇到 I/O 操作时会释放 GIL
  3. 强制释放:Python 解释器会定期强制释放 GIL,让其他线程有机会执行
# -*- coding: utf-8 -*-
import threading
import time


def count_down(n):
    while n > 0:
        n -= 1


print("检查是否输入数据", 50000000 * 2 / 100000000)

# 单线程执行
start = time.time()
count_down(100000000)
print(f"单线程耗时: {time.time() - start:.4f}秒")
# 多线程执行
threads = []
start = time.time()
for i in range(2):
    t = threading.Thread(target=count_down, args=(50000000,))
    threads.append(t)
    t.start()

for t in threads:
    t.join()
print(f"双线程耗时: {time.time() - start:.4f}秒")

# 检查是否输入数据 1.0
# 单线程耗时: 1.8081秒
# 双线程耗时: 1.7343秒

在上述代码中,由于 GIL 的存在,双线程版本可能比单线程版本更慢,因为线程切换带来了额外开销。

GIL 存在的原因

GIL 主要出于以下考虑:

  1. 简化内存管理:Python 使用引用计数进行内存管理,GIL 确保引用计数的修改是线程安全的
  2. 保护 C 扩展:许多 C 扩展库不是线程安全的,GIL 提供了保护
  3. 历史原因:GIL 在 Python 早期就被引入,移除它需要大量工作

GIL 对并发的限制

1. CPU 密集型任务

对于 CPU 密集型任务,GIL 严重限制了多线程的性能提升:

# -*- coding: utf-8 -*-
import threading
import time


def cpu_bound_task():
    count = 0
    for i in range(10 ** 7):
        count += i


# 单线程
start = time.time()
cpu_bound_task()
print(f"单线程 CPU 密集型任务: {time.time() - start:.4f}秒")

# 多线程
threads = []
start = time.time()
for _ in range(2):
    t = threading.Thread(target=cpu_bound_task)
    threads.append(t)
    t.start()

for t in threads:
    t.join()
print(f"双线程 CPU 密集型任务: {time.time() - start:.4f}秒")

# 单线程 CPU 密集型任务: 0.2602秒
# 双线程 CPU 密集型任务: 0.4866秒

2. I/O 密集型任务

对于 I/O 密集型任务,GIL 的影响较小,因为在等待 I/O 操作时会释放 GIL:

# -*- coding: utf-8 -*-
import threading
import time
import requests


def io_bound_task():
    response = requests.get('https://www.python.org')
    return len(response.content)


# 单线程
start = time.time()
for _ in range(5):
    io_bound_task()
print(f"单线程 I/O 密集型任务: {time.time() - start:.4f}秒")

# 多线程
threads = []
start = time.time()
for _ in range(5):
    t = threading.Thread(target=io_bound_task)
    threads.append(t)
    t.start()

for t in threads:
    t.join()
print(f"五线程 I/O 密集型任务: {time.time() - start:.4f}秒")

# 单线程 I/O 密集型任务: 1.4823秒
# 五线程 I/O 密集型任务: 0.4828秒

绕过 GIL 限制的方法

1. 使用多进程

# -*- coding: utf-8 -*-
import multiprocessing
import time


def cpu_bound_task():
    count = 0
    for i in range(10 ** 7):
        count += i


# 多进程
processes = []
start = time.time()
for _ in range(2):
    p = multiprocessing.Process(target=cpu_bound_task)
    processes.append(p)
    p.start()

for p in processes:
    p.join()
print(f"双进程 CPU 密集型任务: {time.time() - start:.4f}秒")

# 双进程 CPU 密集型任务: 0.0427秒

2. 使用 C 扩展

编写 C 扩展可以在执行期间释放 GIL:

// 示例 C 扩展代码
static PyObject* my_function(PyObject* self, PyObject* args) {
    // 释放 GIL
    Py_BEGIN_ALLOW_THREADS
    
    // 执行 CPU 密集型操作
    // ...
    
    // 重新获取 GIL
    Py_END_ALLOW_THREADS
    
    Py_RETURN_NONE;
}

3. 使用异步编程

对于 I/O 密集型任务,可以使用 asyncio:


# -*- coding: utf-8 -*-
import asyncio
import aiohttp
import time


async def fetch_url(session, url):
    async with session.get(url, verify_ssl=False) as response:
        return await response.text()


async def main():
    async with aiohttp.ClientSession() as session:
        tasks = [fetch_url(session, 'https://www.python.org') for _ in range(5)]
        await asyncio.gather(*tasks)


start = time.time()
asyncio.run(main())
print(f"异步 I/O 密集型任务: {time.time() - start:.4f}秒")
# 异步 I/O 密集型任务: 1.3281秒

GIL 的未来

Python 社区一直在讨论移除 GIL 的可能性:

  1. PyPy-STM:已经实现了无 GIL 的版本,但尚未成熟
  2. Python 3.13:计划引入一个可选的无 GIL 模式
  3. PEP 703:提出了使 GIL 成为可选的提案

总结

GIL 是 CPython 解释器中的一个重要机制,它简化了内存管理和 C 扩展的集成,但也限制了多线程在 CPU 密集型任务中的性能。对于 I/O
密集型任务,多线程仍然有效,因为 I/O 操作会释放 GIL。对于 CPU 密集型任务,可以考虑使用多进程、C 扩展或异步编程来绕过 GIL 的限制。

理解 GIL 的工作原理和限制,有助于开发者选择合适的并发模型,从而编写出更高效的 Python 程序。

为什么写这么一遍AI形式的文章。源于字节面试官的无理取闹

- 1. GIL锁限制并发,即可。 因为我不会修改GIL如何内部工作。仅了解是什么原因限制。

- 2. 源于实际工作中,我只要使用好多线程,多进程,多协程模块。完成Task即可,只需要看Task通过这些模块能否提高Task效率,通往罗马的路不止一条。

- 3. 面试官,你真的了解GIL锁吗?或者你参与过Python新版本修改工作吗?你是Producer?你是Owner?还是你是Creater?

- 4. 纯吐槽,外包仔的呐喊🎉!!!

posted @ 2026-01-19 17:50  染指未来  阅读(0)  评论(0)    收藏  举报