Python线程中两种join()调用方式的差异是什么?
关于Python threading中join()方法位置的差异解析
问题描述
我想用threading包计算数字的平方,写了如下代码,但对join()方法的放置位置感到困惑——虽然两种写法输出结果相同,但猜测存在差异,想了解具体区别:
import threading def my_squr(num): #if this function take long time to run print(num*num) return num*num if __name__ == "__main__": l1 = [1,3,5,7,11,13,15,17] for i, item in enumerate(l1): if i % 3 == 0: t1 = threading.Thread(target=my_squr, args=(item,)) t1.start() t1.join() elif i % 3 == 1: t2 = threading.Thread(target=my_squr, args=(item,)) t2.start() t2.join() else: t3 = threading.Thread(target=my_squr, args=(item,)) t3.start() t3.join() # t1.join() # t2.join() # t3.join() print("Done")
两种join()写法的核心区别
1. 循环内调用join()(当前代码的写法)
这种写法本质是串行执行所有线程:
- 每启动一个线程后立刻调用
t.join(),会强制主线程暂停,直到这个子线程完全执行完毕,才会进入下一次循环处理下一个元素 - 相当于放弃了多线程的并发优势,和直接在主线程里逐个调用
my_squr(item)没有区别 - 如果
my_squr是耗时任务(比如加time.sleep(1)),总耗时等于所有任务执行时间的总和(比如8个任务各耗时1秒,总耗时8秒)
2. 循环外调用join()(注释写法需修正后才正确)
原注释中的写法有bug:t1/t2/t3会被循环多次赋值,最后join()的只是最后一次创建的线程,前面的线程未被主线程等待。正确的做法是把所有线程对象存入列表再统一join():
import threading def my_squr(num): print(num*num) return num*num if __name__ == "__main__": l1 = [1,3,5,7,11,13,15,17] threads = [] for item in l1: t = threading.Thread(target=my_squr, args=(item,)) threads.append(t) t.start() # 统一等待所有线程完成 for t in threads: t.join() print("Done")
这种写法的核心是并发执行所有线程:
- 先一次性启动所有子线程,让它们同时运行(IO密集型任务能明显提升效率,CPU密集型受Python GIL限制效果有限,但逻辑上是并发)
- 主线程最后等待所有子线程执行完毕后,才会打印
Done - 如果
my_squr是耗时任务,总耗时等于单个任务的最长执行时间(比如8个任务各耗时1秒,总耗时约1秒)
为什么两种写法结果看起来相同?
因为你的my_squr是极快的计算任务,线程启动和执行的时间可以忽略不计,串行和并发的执行效果在输出上几乎没有差别。如果给my_squr加上耗时操作(比如time.sleep(1)),就能立刻看到两种写法的耗时差异。
内容的提问来源于stack exchange,提问作者4daJKong
相关产品推荐
相关产品推荐

