threading.Thread不执行目标函数的主因是target传了函数调用(如my_func())而非函数引用(my_func),且主线程未调用join()导致子线程被终止;CPU密集型任务无加速源于GIL限制,应改用multiprocessing或numpy等绕过GIL的方案。

为什么 threading.Thread 启动后不执行目标函数?
常见现象是调用了 t.start(),但 target 函数毫无反应。根本原因通常是:把函数调用写成了函数引用 —— 例如传了 target=my_func()(带括号),实际应传 target=my_func(不带括号)。
另一个高频坑是主线程结束太快,子线程被强制终止(尤其在脚本末尾没加 t.join())。Python 的 threading 模块不会自动等待子线程完成。
实操建议:
- 检查
target参数是否为函数名本身,而非调用表达式 - 所有启动的
Thread实例,若需确保其执行完毕,必须显式调用.join() - 避免在
target函数中直接修改全局变量而不加锁 —— 即使看起来“只是读”,也可能因字节码交错引发意外
用 queue.Queue 在多线程间安全传数据,但程序卡死?
典型表现是生产者调用 q.put(item) 后阻塞,或消费者调用 q.get() 后永远等不到数据。这不是队列“坏了”,而是没理解 queue.Queue 的阻塞机制和配套方法语义。
关键点:
立即学习“Python免费学习笔记(深入)”;
-
q.get()默认阻塞,直到有数据;若确定队列非空,可加timeout=1避免无限等待 - 使用
q.task_done()必须与q.join()配对 —— 每次get()后处理完任务,就得调一次task_done(),否则join()永远不会返回 -
q.empty()和q.qsize()在多线程下不可靠,仅作粗略参考,不能用于条件判断逻辑
为什么 CPU 密集型任务用 threading 几乎不提速?
这是 Python 的 GIL(全局解释器锁)导致的硬限制:同一时刻只有一个线程执行 Python 字节码。所以纯计算任务(如循环累加、正则匹配大量文本、数值计算)无法通过多线程并行利用多核。
应对策略取决于场景:
- 如果任务含 I/O(文件读写、网络请求、数据库查询),
threading依然有效 —— I/O 时 GIL 会释放,其他线程可运行 - 若确实是 CPU 密集型,改用
multiprocessing模块,每个进程有独立解释器和 GIL - 部分计算可用
numpy或scipy加速 —— 它们的底层 C 实现绕过 GIL,此时多线程也能受益
调试多线程时,print 输出乱序甚至缺失?
不是 bug,是标准输出(sys.stdout)默认行缓冲 + 线程竞争的结果。多个线程同时调 print(),可能把不同线程的字符串碎片混在一起,或因缓冲未刷新而丢失。
临时解决办法(仅限调试):
- 给
print()加flush=True参数,如print("msg", flush=True) - 用
logging模块替代 —— 它线程安全,且支持格式化和输出定向 - 更稳妥的方式是把日志内容先写入线程本地变量或
queue.Queue,由单个线程统一输出
GIL 不保证 print 原子性,这点容易被忽略 —— 即使只 print 一个变量,背后也涉及对象转换、编码、写缓冲多个步骤,中间可能被切换。











