You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

循环启动多线程后,线程完成打印存在明显延迟的原因分析

问题描述

我写了一个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"的打印间隔问题。

  • 解决办法

    1. 调整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密集型任务依然无法并行,只是启动时机同步了。

    2. 用多进程替代多线程,实现真正并行
      如果想让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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 04:55:29