初学python多线程应从threading.thread入手,避免过早使用concurrent.futures;必须调用start()而非run(),用join()等待结束,传参用args/kwargs,注意gil与i/o阻塞差异,合理使用lock/rlock,重视线程生命周期管理。
☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜

Python 多线程用 threading.Thread 就够,别碰 concurrent.futures 初学时
新手一搜“Python 多线程”,常被 concurrent.futures.ThreadPoolExecutor 带偏——它封装太深,出错时连线程名、异常栈都藏得严实。真想搞懂并发逻辑,从 threading.Thread 入手最直接。
常见错误现象:threading.Thread 启动后主线程立刻退出,子线程没执行完就没了;或者忘了调 start() 直接调 run(),结果变成同步串行。
- 必须调
start(),不是run()——后者只是普通函数调用,不启新线程 - 需要等待子线程结束?加
t.join(),否则主线程跑完整个程序就退出 - 传参用
args=()和kwargs={},别往target里塞带括号的调用,比如target=func()是错的,得是target=func - 线程间共享变量要小心:
list、dict本身不是线程安全的,但 CPython 的 GIL 让简单操作(如append)通常不会崩,别依赖这点做关键逻辑
为什么 time.sleep() 在多线程里不阻塞其他线程,但 requests.get() 会卡住整个线程
time.sleep() 是 Python 主动让出控制权,GIL 会释放,其他线程能抢到;而 requests.get() 底层是 socket 阻塞调用,GIL 不释放,整个线程挂起,别的线程也动不了——这是新手最常误判的点。
使用场景:你要发多个 HTTP 请求又不想等一个完再发下一个,threading 确实能并发,但更稳的选择是 asyncio + aiohttp(I/O 密集型首选),或者至少用 requests 的 timeout 参数防死等。
-
requests.get(url, timeout=5)必加timeout,否则 DNS 卡住或服务无响应,线程就永远挂那了 - 别在线程里用
input()或任何交互式阻塞调用——标准输入是进程级资源,多线程读会乱 - 如果发现“开了 10 个线程,但 QPS 没提升”,大概率是
requests在等连接池、DNS 或远端响应,不是线程没跑起来
threading.Lock 不是万能锁,别在所有共享写操作前都加
加锁太勤反而拖慢性能,甚至引发死锁。Python 的 GIL 已经保住了原子操作(如 counter += 1 实际是三步字节码,不原子),所以真正要锁的,是你明确知道会被多个线程同时修改且操作非原子的结构。
参数差异:Lock 是不可重入的,同一线程重复 acquire() 会死锁;需要重入?换 Rlock。
- 只锁真正临界区,比如
if data: process(data); data.clear()这种判断+清空组合,中间不能插其他线程操作 - 用
with lock:代替手动acquire()/release(),避免忘记释放 - 别锁整个函数体,尤其别把
time.sleep()或requests.get()包进锁里——这等于把其他线程按在地上等你发完请求 - 两个锁嵌套时,固定获取顺序(比如总先锁 A 再锁 B),否则容易死锁
千问AI 辅助写多线程代码时,最容易忽略的其实是线程生命周期管理
AI 给的示例常聚焦“怎么启线程”,但真实项目里,线程什么时候停、怎么通知它停、异常后是否自动重启、日志怎么区分线程上下文——这些才是线上出问题的地方。
性能影响:不管理生命周期会导致僵尸线程堆积,ps aux | grep python 能看到一堆 “defunct”;兼容性上,Windows 对线程数量更敏感,开太多可能直接报 OSError: can't start new thread。
- 用
threading.Event做退出信号,比全局 flag 变量可靠得多 - 线程函数里包一层
try/except Exception,至少把异常打出来,否则线程静默退出你根本不知道 - 给线程起名:
Thread(target=worker, name="fetcher-01"),查日志、调试时能一眼对应 - 别让线程函数无限循环却没 sleep——CPU 占满不说,还可能饿死其他线程
线程不是“开了就完事”,它和文件句柄、数据库连接一样,是需要显式清理的资源。很多人卡在这一步,不是不会写并发,是忘了它本质上是个状态机。











