亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Industrial programming >> Python

Python 多线程精通:GIL 详解与实战示例

Python 提供多进程和多线程加速工作负载。本指南带你创建健壮的线程应用,深入理解全局解释器锁 (GIL),并规避死锁、竞态条件等常见陷阱。

什么是线程?

线程是单进程内的轻量执行单元。线程共享进程内存空间,实现高效数据交换,操作系统将其调度在单个或多个 CPU 核心上并发运行。

什么是进程?

进程是独立程序实例。启动应用(如浏览器、文本编辑器)时,OS 创建独立进程,拥有自己的代码、数据和内存映射。

Python 多线程基础

Python threading 模块提供高级 API 管理线程,遗留 _thread 模块已弃用仅保留兼容性。线程适合 I/O 密集型任务,CPU 密集型工作应用 multiprocessing 绕过 GIL。

何时使用多线程

多线程在同时执行多个 I/O 密集操作(网络请求、文件 I/O、数据库调用)时大放异彩。设计得当的线程能提升响应性和吞吐量,避免创建新进程的开销。

Python 线程关键模块

  1. _thread —— 低级、已弃用。
  2. 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))

运行产生交错输出,展示并发执行。

Python 多线程精通:GIL 详解与实战示例

解释

  1. 导入 time 和遗留 _thread 模块。
  2. 定义 thread_test 执行工作并记录进度。
  3. 通过 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()

输出:

Python 多线程精通:GIL 详解与实战示例

解释

  1. 继承 Thread 封装线程行为。
  2. 重写 __init__ 存储线程专属数据。
  3. 重写 run 定义任务。
  4. 实例化、启动、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()

输出演示临界区串行化访问。

Python 多线程精通:GIL 详解与实战示例

其他同步工具

理解全局解释器锁 (GIL)

CPython 用 GIL 序列化跨线程字节码执行。虽保护解释器内部结构(如引用计数)免受竞态条件,但也限制多核系统上 CPU 密集型任务的并行性。

  1. 线程启动时获取 GIL。
  2. 另一线程需 GIL 时阻塞直到释放。
  3. I/O 密集线程在阻塞调用期间释放 GIL,允许其他线程运行。
  4. CPU 密集线程持有 GIL,阻止其他线程执行 Python 代码。

因此,Python 多线程在计算密集型负载收益有限;multiprocessing 是此类场景首选。

GIL 存在的原因

CPython 垃圾回收依赖引用计数。无全局锁,并发更新引用计数会导致竞态条件和内存损坏。逐对象锁开销大,GIL 作为简单有效方案被采用。

实战要点

Python

  1. C 语言 free() 函数实战指南:正确释放动态内存、防泄漏与避坑全解析
  2. C# 多线程编程精通:提升性能与效率的核心技术
  3. Python strip() 方法完全指南:去除首尾空白与自定义字符实战
  4. Python str.count() 完全指南:统计字符与子串出现次数实战
  5. Python round() 函数详解与实战示例
  6. 精通 Python map() 函数:语法、示例与最佳实践
  7. Python timeit():精准测量代码执行时间与实战示例
  8. Python collections.Counter:高效计数、更新与算术运算
  9. Python list.count() 专家指南:语法、示例与性能解析
  10. Python list.index() 详解:查找元素位置的实用指南与示例
  11. Python 多线程编程精通:高效并发技术全解析
  12. Python C 扩展开发指南:构建高性能原生模块