探究thread.join()

发布时间:2023-05-19

一、join()方法介绍

在Python的多线程编程中,指定线程(t)调用join()方法表示等待该线程执行完成,才开始执行后续代码。

join()方法可以传入一个可选的参数表示等待的时间,以秒为单位。

若不传入参数则默认为阻塞主线程,直到指定线程完成为止。


import threading
import time

def foo():
    for i in range(5):
        print(i)
        time.sleep(1)

t = threading.Thread(target=foo)
t.start()

print("Start")
t.join()
print("Finish")

在上述代码中,调用join()方法会阻塞主线程,找到指定的线程t执行完成为止,然后才会输出"Finish"。

二、join()方法的用例

1. 确保线程执行完成再执行后续代码

在多线程编程中,由于线程的执行是并行的,因此主线程往往无法确定子线程何时结束,因此就需要使用join()方法来确保线程执行完成再执行后续的代码。


import threading
import time

class MyThread(threading.Thread):
    def __init__(self, name):
        super().__init__()
        self.name = name
        
    def run(self):
        print("Start", self.name)
        time.sleep(2)
        print("Finish", self.name)
        
thread_1 = MyThread("Thread 1")
thread_2 = MyThread("Thread 2")

thread_1.start()
thread_2.start()

print("Start")

thread_1.join()
thread_2.join()

print("Finish")

在上述代码中,我们创建了两个MyThread线程,并通过调用start()方法启动它们。再使用join()方法来等待线程执行完成并输出"Finish"。

2. 限制线程执行时间

join()方法的一个可选参数是timeout,表示最多等待的时间,以秒为单位。若在timeout时间内指定线程都没有执行完成,则会自动停止等待,并在后续代码继续执行。


import threading
import time

class MyThread(threading.Thread):
    def __init__(self, name):
        super().__init__()
        self.name = name
        
    def run(self):
        print("Start", self.name)
        time.sleep(5)
        print("Finish", self.name)
        
thread_1 = MyThread("Thread 1")

thread_1.start()

print("Start")

thread_1.join(2)

print("Finish")

在上述代码中,我们创建了一个MyThread线程,并通过调用start()方法启动它。然后使用join()方法,并传入2秒作为超时时间,表示等待最多2秒,如果线程没有完成则自动停止等待。

3. 阻塞主线程等待线程执行完成

如果调用join()方法时,不传入任何参数,那么默认就会阻塞主线程,直到指定线程执行完成为止。


import threading
import time

class MyThread(threading.Thread):
    def __init__(self, name):
        super().__init__()
        self.name = name
        
    def run(self):
        print("Start", self.name)
        time.sleep(5)
        print("Finish", self.name)
        
thread_1 = MyThread("Thread 1")

thread_1.start()

print("Start")

thread_1.join()

print("Finish")

在上述代码中,我们创建了一个MyThread线程,并通过调用start()方法启动它。然后在调用join()方法时不传入任何参数,默认会阻塞主线程,直到线程执行完成。

三、join()方法的注意事项

1. join()方法的顺序

在调用多个线程的join()方法时,需要注意join()方法的顺序。如果A线程需要等待B线程执行完成才能执行,那么应该先让B线程调用join()方法再让A线程调用join()方法。


import threading
import time

class MyThread(threading.Thread):
    def __init__(self, name):
        super().__init__()
        self.name = name
        
    def run(self):
        print("Start", self.name)
        time.sleep(5)
        print("Finish", self.name)
        
thread_1 = MyThread("Thread 1")
thread_2 = MyThread("Thread 2")

thread_1.start()
thread_2.start()

print("Start")

thread_2.join()
thread_1.join()

print("Finish")

在上述代码中,我们创建了两个MyThread线程,并通过调用start()方法启动它们。先让B线程调用join()方法,然后才让A线程调用join()方法。

2. join()方法的使用时机

在使用join()方法时,需要考虑使用的时机。如果在程序中过早或过晚调用join()方法,都会对程序的性能产生影响。

过早调用join()方法可能会降低并发性能,并导致程序变慢。过晚调用join()方法则可能会导致线程不释放。

3. 线程间通信

join()方法属于线程同步的一种方式,可以用于线程间通信,但不是最佳的线程间通信方式。

在Python的多线程编程中,使用Queue队列和Condition条件变量更适合进行线程间通信。

结语

join()方法在Python的多线程编程中是一个非常常用的方法。它能够阻塞主线程,确保指定的线程执行完成后再执行后续代码,并且可以通过给join()方法传递不同的参数,来控制线程的执行顺序和等待时间。

在使用join()方法时,需要注意join()方法的顺序和使用的时机,以避免对程序的性能产生影响。