循环启动多线程后,线程完成打印存在明显延迟的原因分析
我写了一个th()函数,它会计数到指定数值后打印"done"。我想同时启动n个这样的线程并行运行,代码如下:
thread_num = 3 # 这里n设为3,但实际我想要更大的数值 thrds = [] i = 0 while i < thread_num: thr = Thread(target=th, args=()) thrds.append(thr) i += 1 print("thread", str(i), "added") for t in thrds: t.start() t.join()
我原本期望所有线程能同时打印"done",但它们的打印有明显延迟。线程启动提示看起来是同时出现的,但"done"的打印间隔很长。这是为什么?
补充的th()函数代码:
def th(): v = 0 num = 10**7 while v < num: v += 1 print("done")
核心原因:Python的GIL(全局解释器锁)限制
CPython解释器的GIL机制,会确保同一时刻只有一个线程能执行Python字节码。你的th()是纯CPU密集型任务,所有线程都在争抢GIL,根本没法真正并行执行。看起来线程是同时启动了,但实际它们是交替占用CPU——一个线程执行一段时间后释放GIL,另一个才能继续跑,所以每个线程的计数任务是串行完成的,自然"done"的打印会有明显间隔。代码隐藏问题:
join()的位置错了
你在循环里启动一个线程就立刻调用t.join(),这会让主线程等当前线程完全跑完,才会启动下一个线程!也就是说你的线程根本不是并行启动的,是串行执行的:第一个线程跑完打印"done",第二个才开始跑,接着是第三个。这直接加剧了"done"的打印间隔问题。解决办法
调整
join()的位置,让线程真正同时启动
先把所有线程都启动,再统一调用join()等待所有线程结束。修改后的代码:thread_num = 3 thrds = [] for i in range(thread_num): thr = Thread(target=th, args=()) thrds.append(thr) print("thread", str(i+1), "added") # 先批量启动所有线程 for t in thrds: t.start() # 再统一等待所有线程结束 for t in thrds: t.join()调整后线程会同时启动,但由于GIL限制,CPU密集型任务依然无法并行,只是启动时机同步了。
用多进程替代多线程,实现真正并行
如果想让CPU密集型任务真正并行执行,得用multiprocessing模块的Process类——每个进程有独立的Python解释器和GIL,能利用多核CPU的优势。示例代码:from multiprocessing import Process def th(): v = 0 num = 10**7 while v < num: v += 1 print("done") if __name__ == "__main__": thread_num = 3 procs = [] for i in range(thread_num): proc = Process(target=th, args=()) procs.append(proc) print("process", str(i+1), "added") for p in procs: p.start() for p in procs: p.join()这样多个计数任务就能真正并行跑起来,"done"的打印会几乎同时出现。
内容的提问来源于stack exchange,提问作者Shoto Todoroki

