What is the purpose of using Python thread join() in this scenario?

What is the use of join() in Python threading?

I was studying Python threading and came across the join() method. The author mentioned that when a thread is in daemon mode, we need to use join() to ensure the thread completes before the main thread terminates. However, I have also seen the author using t.join() even when the thread t was not set to daemon mode.

Here’s an example code I encountered:

import threading
import time
import logging

logging.basicConfig(level=logging.DEBUG,
                    format='(%(threadName)-10s) %(message)s',
                    )

def daemon():
    logging.debug('Starting')
    time.sleep(2)
    logging.debug('Exiting')

d = threading.Thread(name='daemon', target=daemon)
d.setDaemon(True)

def non_daemon():
    logging.debug('Starting')
    logging.debug('Exiting')

t = threading.Thread(name='non-daemon', target=non_daemon)

d.start()
t.start()

d.join()
t.join()

I don’t understand the use of t.join() here, as the thread t is not a daemon thread. I can’t see any difference even if I remove t.join().

What is the purpose of using Python thread join() in this scenario?

The join() method ensures that the main thread waits for the threads to complete their execution before proceeding.

In this case, t.join() ensures that the non-daemon thread t completes execution before the main program exits. Without it, the main thread may terminate while t is still running, which might be undesirable.

Even though t is not a daemon thread, using t.join() helps ensure that the main thread will wait for t to finish. Without the join(), the main thread could finish before t, and you might not see all the log outputs from t or experience inconsistencies in the execution order.

In daemon threads (like d in the example), the program will exit as soon as the main thread finishes, even if the daemon thread hasn’t been completed.

For non-daemon threads, join() ensures that the main thread waits for them to finish. If t.join() is removed, the program might exit before t has logged its output. The difference lies in whether the program waits for non-daemon threads to finish or not.