join是用于阻塞该行代码所在的线程,让.join()前面线程优先执行的函数,.join()前面线程结束后,该行代码才会继续执行下去,所以join相当于一个线程发出的指令,告诉当前行所在线程,暂停,让我先执行。
两个线程相当于两个人,在不同跑道上,这个跑道需要4步才能跑完,但是两个人的速度不一样,线程1一步需要1s,线程2一步需要0.5s,不加join执行结果如下:
import threading
import time
def test():
for i in range(5):
print(threading.current_thread().name, '跑了', i, '步')
time.sleep(1)
def test2():
for i in range(5):
print(threading.current_thread().name, '跑了', i, '步')
time.sleep(0.5)
thread1 = threading.Thread(target=test, name='子线程1')
thread2 = threading.Thread(target=test2, name='子线程2')
thread1.start()
thread2.start()
start()相当于起跑,test和test2同时执行,执行速度上,线程1速度比线程2慢,最后还是线程2先跑完4步,然后线程1才跑完
子线程1 跑了 0 步
子线程2 跑了 0 步
子线程2 跑了 1 步
子线程1 跑了 1 步
子线程2 跑了 2 步
子线程2 跑了 3 步
子线程1 跑了 2 步
子线程2 跑了 4 步 # 线程2先跑完4步
子线程1 跑了 3 步
子线程1 跑了 4 步
另一场比赛,两个线程同时起跑时,线程1突然拦在线程2的赛道(test2)上,不讲武德的拿出枪(join),说,你再跑一个试试
线程2屈服了,于是站在原地,等线程1跑完4步后,再开始跑
import threading
import time
def test():
for i in range(5):
print(threading.current_thread().name, '跑了', i, '步')
time.sleep(1)
def test2():
print('子线程2:我准备跑')
thread1.join() # 拦住线程2
print('子线程2:我继续跑')
for i in range(5):
print(threading.current_thread().name, '跑了', i, '步')
time.sleep(0.5)
thread1 = threading.Thread(target=test, name='子线程1')
thread2 = threading.Thread(target=test2, name='子线程2')
thread1.start()
thread2.start()
可以看到,线程2 准备跑的时候,突然停住了,让线程1跑完,才敢继续
子线程1 跑了 0 步
子线程2:我准备跑
子线程1 跑了 1 步
子线程1 跑了 2 步
子线程1 跑了 3 步
子线程1 跑了 4 步
子线程2:我继续跑
子线程2 跑了 0 步
子线程2 跑了 1 步
子线程2 跑了 2 步
子线程2 跑了 3 步
子线程2 跑了 4 步
由于观众不满这种毫无观赏性的比赛,于是线程1不得不想出其他方式,比如跟线程2商量,让我先跑2步(join(2)),然后你再跑
def test2():
print('子线程2:我准备跑')
thread1.join(2) # 拦住线程2,让它等待2s
print('子线程2:我继续跑')
for i in range(5):
print(threading.current_thread().name, '跑了', i, '步')
time.sleep(0.5)
尽管线程2等了2s再跑,最后两个人还是几乎同时到达终点,
子线程1 跑了 0 步
子线程2:我准备跑
子线程1 跑了 1 步
子线程2:我继续跑
子线程2 跑了 0 步
子线程1 跑了 2 步
子线程2 跑了 1 步
子线程1 跑了 3 步
子线程2 跑了 2 步
子线程2 跑了 3 步
子线程1 跑了 4 步
子线程2 跑了 4 步
可以把主线程当做test2()函数中的执行部分,效果也是一样的,主线程会等待发出join指令的那个线程先执行。
守护线程
主线程执行完了,子线程不管有没有执行完,都要结束。
主线程听了两个人跑步的故事,也想来参与下,于是就线程1陪主线程玩
import threading
import time
def test():
for i in range(5):
print(threading.current_thread().name, '跑了', i, '步')
time.sleep(1)
thread1 = threading.Thread(target=test, name='子线程1')
thread1.start()
for i in range(5):
print(threading.current_thread().name, '跑了', i, '步')
time.sleep(0.5)
子线程1 跑了 0 步
MainThread 跑了 0 步
MainThread 跑了 1 步
子线程1 跑了 1 步
MainThread 跑了 2 步
MainThread 跑了 3 步
子线程1 跑了 2 步
MainThread 跑了 4 步
子线程1 跑了 3 步
子线程1 跑了 4 步
跑了几次下来主线程发现线程1总是那么慢,每次跑完4步了线程1才跑2步,于是跟线程1说,剩下两步也别跑了,毁灭吧(setDaemon(True)),他累了
import threading
import time
def test():
for i in range(5):
print(threading.current_thread().name, '跑了', i, '步')
time.sleep(1)
thread1 = threading.Thread(target=test, name='子线程1')
thread1.setDaemon(True) # 启动前,先设置守护线程
thread1.start()
for i in range(5):
print(threading.current_thread().name, '跑了', i, '步')
time.sleep(0.5)
后面每次陪跑,线程1都只跑了一半,还有2步没跑,就结束了
子线程1 跑了 0 步
MainThread 跑了 0 步
MainThread 跑了 1 步
子线程1 跑了 1 步
MainThread 跑了 2 步
MainThread 跑了 3 步
子线程1 跑了 2 步
MainThread 跑了 4 步
终于有一天,线程1无法再忍受这种生活,拿出了枪(join),说,让我先跑
import threading
import time
def test():
for i in range(5):
print(threading.current_thread().name, '跑了', i, '步')
time.sleep(1)
thread1 = threading.Thread(target=test, name='子线程1')
thread1.setDaemon(True) # 设置守护线程
thread1.start()
print('主线程:我开始跑')
thread1.join() # 拦住主线程
print('主线程:我继续跑')
for i in range(5):
print(threading.current_thread().name, '跑了', i, '步')
time.sleep(0.5)
主线程对拿枪的线程1并没有什么好办法,只能让他先跑
子线程1 跑了 0 步
主线程:我开始跑
子线程1 跑了 1 步
子线程1 跑了 2 步
子线程1 跑了 3 步
子线程1 跑了 4 步
主线程:我继续跑
MainThread 跑了 0 步
MainThread 跑了 1 步
MainThread 跑了 2 步
MainThread 跑了 3 步
MainThread 跑了 4 步
join所完成的工作就是线程同步,即主线程任务结束之后,进入阻塞状态,一直等待其他的子线程执行结束之后,主线程再终止