当前位置:首页>python>【一起学 Python】第 68 天:全局解释器锁 (GIL) 的现状与 3.14 的无 GIL 模式

【一起学 Python】第 68 天:全局解释器锁 (GIL) 的现状与 3.14 的无 GIL 模式

  • 2026-09-02 18:59:24
【一起学 Python】第 68 天:全局解释器锁 (GIL) 的现状与 3.14 的无 GIL 模式

欢迎来到 Python 学习计划的第 68 天!🎉

昨天我们学习了 生成器的优势:惰性计算与内存节省,掌握了如何高效处理大数据。今天我们将深入 Python 并发的底层机制——全局解释器锁(GIL)。

理解 GIL 是选择正确并发方案的关键!这也是 Python 3.13/3.14 最重要的变革之一。

一、什么是 GIL?

1. 核心定义

GIL(Global Interpreter Lock,全局解释器锁) 是 CPython 解释器中的一个互斥锁,它确保同一时刻只有一个线程执行 Python 字节码。

这意味着即使在多核 CPU 上,Python 的多线程程序也无法真正并行执行 Python 代码。

import threadingimport timecounter = 0def increment():    global counter    for _ in range(1000000):        counter += 1# 即使使用多线程,由于 GIL 的存在,不会真正并行threads = [threading.Thread(target=increment) for _ in range(4)]for t in threads:    t.start()for t in threads:    t.join()print(counter)  # 结果不确定,因为 counter += 1 不是原子操作

2. GIL 存在的原因

原因

说明

内存管理安全

Python 使用引用计数进行垃圾回收,GIL 保护引用计数不会出错

简化 C 扩展开发

C 扩展不需要考虑复杂的线程同步

单线程性能

GIL 使单线程程序更快(无锁开销)

历史原因

Python 诞生时多核 CPU 还不普及

💡 关键点:GIL 不是 Python 语言的缺陷,而是 CPython 实现的特性。其他实现如 Jython、IronPython 没有 GIL。

二、GIL 的影响

1. CPU 密集型任务

GIL 限制了 CPU 密集型任务的多线程性能,多线程甚至可能更慢(因为线程切换有开销)。

import threadingimport timedef cpu_intensive():    total = 0    for i in range(10000000):        total += i    return total# 单线程start = time.time()cpu_intensive()cpu_intensive()print(f"单线程:{time.time() - start:.2f}秒")# 多线程(由于 GIL,不会更快)start = time.time()t1 = threading.Thread(target=cpu_intensive)t2 = threading.Thread(target=cpu_intensive)t1.start()t2.start()t1.join()t2.join()print(f"多线程:{time.time() - start:.2f}秒")  # 时间相近甚至更慢

2. I/O 密集型任务

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

import threadingimport timedef io_intensive():    time.sleep(1)  # 模拟 I/O 等待,此时会释放 GIL# 多线程处理 I/O 是有效的start = time.time()threads = [threading.Thread(target=io_intensive) for _ in range(4)]for t in threads:    t.start()for t in threads:    t.join()print(f"4 个 I/O 任务:{time.time() - start:.2f}秒")  # 约 1 秒,而非 4 秒

3. 任务类型对比

任务类型

特点

GIL 影响

推荐方案

CPU 密集型

大量计算

大(无法并行)

多进程

I/O 密集型

网络/文件等待

小(等待时释放)

多线程/Asyncio

混合任务

计算 +I/O

中等

多进程 + 异步

三、绕过 GIL 的方法

方法 1:使用多进程

多进程可以真正并行,因为每个进程有独立的 Python 解释器和 GIL。

from multiprocessing import Poolimport timedef cpu_intensive(n):    total = 0    for i in range(n):        total += i    return totalif __name__ == "__main__":    # 多进程可以真正并行    start = time.time()    with Pool(4) as p:        results = p.map(cpu_intensive, [10000000] * 4)    print(f"多进程:{time.time() - start:.2f}秒")

方法 2:使用 C 扩展

NumPy 等库在执行计算时会释放 GIL。

import numpy as npimport threading# NumPy 操作可以并行def numpy_operation():    a = np.random.rand(1000, 1000)    return np.dot(a, a)# NumPy 在计算时释放 GIL,可以真正并行threads = [threading.Thread(target=numpy_operation) for _ inrange(4)]for t in threads:    t.start()for t in threads:    t.join()

方法 3:使用 Asyncio

对于 I/O 密集型任务,异步编程是更好的选择(明天详细学习)。

import asyncioasync def fetch_data(url):    await asyncio.sleep(1)  # 模拟网络请求    return f"Data from {url}"async def main():    urls = ["url1", "url2", "url3", "url4"]    tasks = [fetch_data(url) for url in urls]    results = await asyncio.gather(*tasks)    print(results)asyncio.run(main())  # 4 个任务约 1 秒完成

四、OOP 实战应用(结合知识库)

1. 线程安全计数器

import threadingclass ThreadSafeCounter:    """线程安全计数器"""    def __init__(self):        self._value = 0        self._lock = threading.Lock()    def increment(self):        with self._lock:            self._value += 1    def get_value(self):        with self._lock:            return self._value# 使用counter = ThreadSafeCounter()threads = []for _ in range(10):    t = threading.Thread(target=lambda: [counter.increment() for _ in range(1000)])    threads.append(t)    t.start()for t in threads:    t.join()print(f"最终计数:{counter.get_value()}")  # 10000(准确)

2. 线程安全缓存

import threadingfrom typing import Any, Optionalclass ThreadSafeCache:    """线程安全缓存"""    def __init__(self):        self._cache: dict[str, Any] = {}        self._lock = threading.Lock()    def get(self, key: str) -> Optional[Any]:        with self._lock:            return self._cache.get(key)    def set(self, key: str, value: Any) -> None:        with self._lock:            self._cache[key] = value    def delete(self, key: str) -> bool:        with self._lock:            if key in self._cache:                del self._cache[key]                return True            return False# 使用cache = ThreadSafeCache()cache.set("user:1", {"name": "张三"})print(cache.get("user:1"))

3. 工作池模式

from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutorimport timedef cpu_task(n):    return sum(range(n))def io_task(n):    time.sleep(1)    return n# CPU 密集型 -> 多进程with ProcessPoolExecutor(max_workers=4) as executor:    results = list(executor.map(cpu_task, [10000000] * 4))# I/O 密集型 -> 多线程with ThreadPoolExecutor(max_workers=4) as executor:    results = list(executor.map(io_task, range(4)))

总结

知识点

说明

GIL

确保同一时刻只有一个线程执行 Python 字节码

CPU 密集型

GIL 限制多线程性能,推荐多进程

I/O 密集型

GIL 影响小,推荐多线程或 asyncio

无 GIL 模式

Python 3.13/3.14 实验性功能

线程安全

无 GIL 后必须正确使用锁

C 扩展

部分库可能不兼容 free-threaded

核心要点

  1. GIL 限制多线程 CPU 密集型任务的并行性能。
  2. I/O 密集型任务不受 GIL 显著影响(等待时释放锁)。
  3. 绕过 GIL 的方法:多进程、C 扩展、Asyncio。
  4. 无 GIL 版本仍处于实验阶段,生产环境谨慎使用。
  5. 根据任务类型选择并发方案是最重要原则。

📌 明日预告:Asyncio 基础:async 与 await

明天我们将进入 并发与迭代模块最后一天!

  • 主题:Asyncio 基础:async 与 await
  • 核心问题:
    1. 什么是异步编程?与同步有什么区别?
    2. async def 和 await 关键字怎么用?
    3. 事件循环(Event Loop)是什么?
    4. asyncio.gather() 和 create_task() 有什么区别?
    5. 实际应用场景有哪些?(HTTP 请求、文件 I/O)

💡 提前思考:

  1. 如果有 100 个网络请求,同步执行需要 100 秒,异步需要多久?
  2. await 和 time.sleep() 有什么区别?
  3. 为什么不能在普通函数中使用 await?

理解 GIL 是选择正确并发方案的基础!明天学习现代 Python 异步编程!继续加油!🚀

最新文章

随机文章