前言
在实现多线程的代码的时候,发现一个大家很容易忽略的关键字join,大家真的很懂join吗?
代码案例
请大家对比下下面两段代码的区别
运行结果
左边图片运行结果
右边图片运行结果
左边运行结果时间是:8+5+3=16好像串行运行 右边好像是并行的,但是为什么是这样呢?
join讲解
所以,如果代码写为:
thread_1.start()
thread_1.join()
thread_2.start()
thread_2.join()
thread_3.start()
thread_3.join()
当代码运行到thread_1.join()时,主线程就卡住了,后面的thread_2.start()根本没有执行。此时当前只有 thread_1执行过.start()方法,所以此时只有 thread_1再运行。这个线程需要执行8秒钟。等8秒过后,thread_1结束,于是主线程才会运行到thread_2.start(),第二个线程才会开始运行。所以这个例子里面,三个线程串行运行,完全是写代码的人有问题。 而当我们把代码写为:
thread_1.start()
thread_2.start()
thread_3.start()
thread_1.join()
thread_2.join()
thread_3.join()
当代码执行到thread_1.join()时,当前三个子线程均已经执行过.start()方法了,所以此时主线程虽然卡住了,但是三个子线程会继续运行。其中线程3先结束,然后线程2结束。此时线程1还剩3秒钟,所以此时thread_1.join()依然是卡住的状态,直到线程1结束,thread_1.join()解除阻塞,代码运行到thread_2.join()中,但由于thread_2早就结束了,所以这行代码一闪而过,不会卡住。同理,thread_3.join()也是一闪而过。所以整个过程中,thread_2.join()和thread_3.join()根本没有起到任何作用。直接就结束了。 所以,你只需要 join 时间最长的这个线程就可以了。时间短的线程没有 join 的必要。根本不需要把这么多个 join 堆在一起。 为什么会有 join 这个功能呢?我们设想这样一个场景。你的爬虫使用10个线程爬取100个 URL,主线程需要等到所有URL 都已经爬取完成以后,再来分析数据。此时就可以通过 join 先把主线程卡住,等到10个子线程全部运行结束了,再用主线程进行后面的操作。 那么可能有人会问,如果我不知道哪个线程先运行完,那个线程后运行完怎么办?这个时候是不是就要每个线程都执行 join 操作了呢? 确实,这种情况下,每个线程使用 join是合理的:
thread_list = []
for _ in range(10):
thread = threading.Thread(target=xxx, args=(xxx, xxx)) 换行thread.start()
thread_list.append(thread)
for thread in thread_list:
thread.join()