Python 多线程精通:GIL 详解与实战示例
Python 提供多进程和多线程加速工作负载。本指南带你创建健壮的线程应用,深入理解全局解释器锁 (GIL),并规避死锁、竞态条件等常见陷阱。
什么是线程?
线程是单进程内的轻量执行单元。线程共享进程内存空间,实现高效数据交换,操作系统将其调度在单个或多个 CPU 核心上并发运行。
什么是进程?
进程是独立程序实例。启动应用(如浏览器、文本编辑器)时,OS 创建独立进程,拥有自己的代码、数据和内存映射。
Python 多线程基础
Python threading 模块提供高级 API 管理线程,遗留 _thread 模块已弃用仅保留兼容性。线程适合 I/O 密集型任务,CPU 密集型工作应用 multiprocessing 绕过 GIL。
- 线程:共享内存、轻量。
- 进程:隔离内存、较重。
- GIL:保护 Python 字节码执行的互斥锁。
何时使用多线程
多线程在同时执行多个 I/O 密集操作(网络请求、文件 I/O、数据库调用)时大放异彩。设计得当的线程能提升响应性和吞吐量,避免创建新进程的开销。
Python 线程关键模块
- _thread —— 低级、已弃用。
- threading —— 现代、功能丰富、推荐选择。
使用 threading 模块
threading 提供 Thread 类、同步原语 (Lock, RLock, Semaphore, Condition, Event, Barrier) 及 activeCount()、enumerate() 等工具函数。下面最小示例演示线程创建与同步。
import time
import _thread
def thread_test(name, wait):
for i in range(4):
time.sleep(wait)
print(f"Running {name}")
print(f"{name} has finished execution")
if __name__ == "__main__":
_thread.start_new_thread(thread_test, ("First Thread", 1))
_thread.start_new_thread(thread_test, ("Second Thread", 2))
_thread.start_new_thread(thread_test, ("Third Thread", 3))
运行产生交错输出,展示并发执行。

解释
- 导入
time和遗留_thread模块。 - 定义
thread_test执行工作并记录进度。 - 通过
start_new_thread启动三个独立线程。
现代 threading.Thread 用法
实践中通常继承 threading.Thread 并重写 run() 方法。下例用高级 API 复现上述行为。
import time
import threading
class ThreadTester(threading.Thread):
def __init__(self, name, delay):
super().__init__()
self.name = name
self.delay = delay
def run(self):
for _ in range(4):
time.sleep(self.delay)
print(f"Running {self.name}")
print(f"{self.name} has finished execution")
if __name__ == "__main__":
threads = [
ThreadTester("First Thread", 1),
ThreadTester("Second Thread", 2),
ThreadTester("Third Thread", 3),
]
for t in threads:
t.start()
for t in threads:
t.join()
输出:

解释
- 继承
Thread封装线程行为。 - 重写
__init__存储线程专属数据。 - 重写
run定义任务。 - 实例化、启动、join 每个线程。
常见线程陷阱
死锁
两个或多个线程无限等待对方持有的资源。经典案例:哲学家进餐问题——五哲学家竞争五叉子,每人需两叉进食。若每人先拿右叉,形成循环等待,所有进程停滞。
竞态条件
多线程无协调修改共享数据导致最终状态不可预测。例如:
i = 0
for _ in range(100):
print(i)
i += 1
并行启动此循环会导致序列混乱,因增量操作重叠。
线程同步
threading 提供多种同步原语。最基础是 Lock,确保独占共享资源。
import threading
lock = threading.Lock()
def worker(name):
for _ in range(5):
lock.acquire()
print(f"{name} acquired lock")
# 临界区
lock.release()
if __name__ == "__main__":
t1 = threading.Thread(target=worker, args=("Thread A",))
t2 = threading.Thread(target=worker, args=("Thread B",))
t1.start(); t2.start()
t1.join(); t2.join()
输出演示临界区串行化访问。

其他同步工具
- RLock —— 可重入锁。
- Semaphore —— 控制有限资源访问。
- Condition —— 让线程等待特定条件。
- Event —— 简单标志用于线程间信号。
- Barrier —— 阻塞一组线程直到全部到达某点。
理解全局解释器锁 (GIL)
CPython 用 GIL 序列化跨线程字节码执行。虽保护解释器内部结构(如引用计数)免受竞态条件,但也限制多核系统上 CPU 密集型任务的并行性。
- 线程启动时获取 GIL。
- 另一线程需 GIL 时阻塞直到释放。
- I/O 密集线程在阻塞调用期间释放 GIL,允许其他线程运行。
- CPU 密集线程持有 GIL,阻止其他线程执行 Python 代码。
因此,Python 多线程在计算密集型负载收益有限;multiprocessing 是此类场景首选。
GIL 存在的原因
CPython 垃圾回收依赖引用计数。无全局锁,并发更新引用计数会导致竞态条件和内存损坏。逐对象锁开销大,GIL 作为简单有效方案被采用。
实战要点
- I/O 密集型并发用
threading。 - CPU 密集型并行首选
multiprocessing。 - 共享数据务必用锁或高级原语同步。
- 跨核扩展时注意 GIL 影响。
- 继承
Thread重写run()编写清晰可维护代码。
Python
- C 语言 free() 函数实战指南:正确释放动态内存、防泄漏与避坑全解析
- C# 多线程编程精通:提升性能与效率的核心技术
- Python strip() 方法完全指南:去除首尾空白与自定义字符实战
- Python str.count() 完全指南:统计字符与子串出现次数实战
- Python round() 函数详解与实战示例
- 精通 Python map() 函数:语法、示例与最佳实践
- Python timeit():精准测量代码执行时间与实战示例
- Python collections.Counter:高效计数、更新与算术运算
- Python list.count() 专家指南:语法、示例与性能解析
- Python list.index() 详解:查找元素位置的实用指南与示例
- Python 多线程编程精通:高效并发技术全解析
- Python C 扩展开发指南:构建高性能原生模块