Understanding Python Threading: Daemon Threads, join() and Timeout
This article explains Python's multithreading basics, covering the default behavior of threads, how daemon threads affect program termination, the role of the join() method for synchronization, and the impact of its timeout parameter, illustrated with clear code examples and execution results.
Overview
In Python, the join() method works the same way for both multithreading and multiprocessing, providing a way to synchronize threads by blocking the main thread until child threads finish.
Python multithreading default behavior
When a process starts, a main thread is created automatically. If additional threads are spawned, the main thread will finish its own work and exit, while child threads continue running until they complete. The following example demonstrates this default behavior:
#!/usr/bin/python #! -*- coding:utf-8 -*- import threading import time import sys reload(sys) sys.setdefaultencoding('utf-8') def run(): time.sleep(2) print('当前线程的名字是: ' + threading.current_thread().name) time.sleep(2) if __name__ == '__main__': start_time = time.time() print('这是主线程:' + threading.current_thread().name) thread_list = [] for i in range(5): t = threading.Thread(target=run) thread_list.append(t) for t in thread_list: t.start() print('主线程结束!' + threading.current_thread().name) print('一共用时:'+ str(time.time()-start_time))
Running this script produces output showing that the main thread ends quickly while child threads continue to print their names.
Setting daemon threads
When setDaemon(True) is used, the child threads become daemon threads; once the main thread finishes, all daemon threads are terminated immediately, regardless of whether they have completed their tasks. Example:
#!/usr/bin/python #! -*- coding:utf-8 -*- import threading import time import sys reload(sys) sys.setdefaultencoding('utf-8') def run(): time.sleep(2) print('当前线程的名字是: ' + threading.current_thread().name) time.sleep(2) if __name__ == '__main__': start_time = time.time() print('这是主线程:' + threading.current_thread().name) thread_list = [] for i in range(5): t = threading.Thread(target=run) thread_list.append(t) for t in thread_list: t.setDaemon(True) t.start() print('主线程结束了!' + threading.current_thread().name) print('一共用时:' + str(time.time()-start_time))
The result shows that the program exits right after the main thread ends, without waiting for the child threads.
The role of join()
Using join() forces the main thread to wait for each child thread to finish, providing proper synchronization. Example:
#!/usr/bin/python #! -*- coding:utf-8 -*- import threading import time import sys reload(sys) sys.setdefaultencoding('utf-8') def run(): time.sleep(2) print('当前线程的名字是: ' + threading.current_thread().name) time.sleep(2) if __name__ == '__main__': start_time = time.time() print('这是主线程:' + threading.current_thread().name) thread_list = [] for i in range(5): t = threading.Thread(target=run) thread_list.append(t) for t in thread_list: t.setDaemon(True) t.start() for t in thread_list: t.join() print('主线程结束了!' + threading.current_thread().name) print('一共用时:' + str(time.time()-start_time))
The output confirms that the main thread only terminates after all child threads have completed.
Key points
The timing measured is for the main thread; when the main thread ends, its timer stops.
Without daemon threads, the main thread waits for all child threads to finish before the program exits.
With daemon threads, the program may exit before child threads complete, unless join() is used.
Python Programming Learning Circle
A global community of Chinese Python developers offering technical articles, columns, original video tutorials, and problem sets. Topics include web full‑stack development, web scraping, data analysis, natural language processing, image processing, machine learning, automated testing, DevOps automation, and big data.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.