Python 多线程从入门到实战:别再让你的程序“单线程”思考

张开发
2026/4/14 22:50:25 15 分钟阅读

分享文章

Python 多线程从入门到实战:别再让你的程序“单线程”思考
前言在刚开始学 Python 的时候我们写的代码通常是“顺序执行”的。就像去食堂排队打饭前面的同学没打完你就得一直等着。但在实际开发中比如爬虫、下载文件、读取数据库很多时候 CPU 其实是在闲置的仅仅是在“等网络回传”或“等硬盘读写”。这时候多线程Multithreading就像是多开了几个打饭窗口。今天我就带大家一起揭开 Python 多线程的神秘面纱。一、 核心概念什么是多线程如果把一个进程比作一家工厂那么线程就是工厂里的工人。单线程工厂只有一个工人干完 A 才能干 B效率低。多线程工厂有多个工人大家同时开工资源共享。个人理解在 Python 中多线程并不是真正的“并行”物理上的同时而是一种“并发”逻辑上的同时。它更像是一个人在多个任务之间快速切换利用任务等待的间隙去干别的。二、 基础实现Threading 模块Python 提供了内置的threading模块来处理多线程。1. 快速上手代码我们先来看一个最简单的对比示例模拟两个耗时 2 秒的任务。import threading import time def task(name, duration): print(f任务 {name} 开始执行...) time.sleep(duration) print(f任务 {name} 执行完毕) # --- 单线程模式 --- start_time time.time() task(A, 2) task(B, 2) print(f单线程总耗时: {time.time() - start_time:.2f} 秒) print(- * 30) # --- 多线程模式 --- start_time time.time() # 创建线程对象 t1 threading.Thread(targettask, args(A, 2)) t2 threading.Thread(targettask, args(B, 2)) # 启动线程 t1.start() t2.start() # 等待线程结束join 的作用是让主程序等子线程执行完再往下走 t1.join() t2.join() print(f多线程总耗时: {time.time() - start_time:.2f} 秒)2. 关键函数解析threading.Thread(target函数名, args(参数,)): 创建线程。注意target传的是函数引用不要带括号。.start(): 激活线程告诉系统可以开始运行了。.join(): 这是一个“阻塞”操作。如果没有它主程序会直接打印最后一句而不管子线程有没有跑完。三、 深度思考为什么 Python 线程有时候“不给力”这是很多新手最困惑的地方为什么我开了 10 个线程处理计算任务速度反而变慢了这里必须提到 Python 的“紧箍咒” ——GILGlobal Interpreter Lock全局解释器锁。1. 什么是 GIL为了保证内存安全Python 的 CPython 解释器限制了同一时刻只能有一个线程在执行 Python 字节码。这意味着即使你有 8 核 CPUPython 线程也无法在物理上实现真正的 8 核并行。2. 场景选择个人总结的军规IO 密集型推荐使用多线程场景网络爬虫、文件读写、数据库请求。原因线程在等待 IO 时会主动释放 GIL 锁让其他线程工作效率大幅提升。计算密集型不推荐使用多线程场景复杂的数学运算、视频解码、图片处理。原因线程会为了争夺 GIL 锁而频繁切换切换带来的开销反而比单线程还慢。这种情况建议使用多进程multiprocessing。四、 实战技巧使用守护线程 (Daemon)有时候我们希望主程序退出时子线程也跟着一起死比如后台监控任务这时可以用daemon属性。t threading.Thread(targetlong_running_task) t.daemon True # 设置为守护线程 t.start() # 主程序结束t 也会强制结束五、 避坑指南线程安全与锁Lock当多个线程同时修改同一个变量时会发生“数据踩踏”。场景两个线程同时对一个变量count进行1操作执行 100 万次结果可能不是 200 万。解决办法使用threading.Lock()。lock threading.Lock() count 0 def safe_add(): global count for _ in range(1000000): with lock: # 使用 context manager 自动获取和释放锁 count 1六、 总结与感悟别盲目多线程先判断你的任务是 IO 型还是计算型。习惯使用 Join确保主程序能拿到子线程的结果。重视线程安全涉及到共享全局变量时一定要加锁。进阶推荐对于简单的任务池可以去了解一下concurrent.futures.ThreadPoolExecutor那是更高级且简洁的写法。多线程是开启高性能 Python 开发的第一步虽然有 GIL 的存在但在网络编程和自动化工具开发中它依然是我们最得力的助手

更多文章