Python主线程与子线程结束顺序详解:守护线程、Join与异常处理
本文深入解析Python中主线程与子线程的结束顺序关系。通过实例说明默认情况下主线程退出后进程会等待非守护子线程执行完毕;若子线程设为守护线程(daemon=True),主线程退出将直接终止该子线程。此外,文章还演示了join()方法的阻塞作用以及主线程发生异常退出时对所有子线程的影响,帮助开发者掌握多线程生命周期管理。
Python多线程结束顺序概述
本文详细解析Python中主线程与子线程的结束顺序,通过具体代码示例展示不同场景下的行为,为相关开发工作提供参考。
参考关于主线程退出对子线程影响的相关论述:
在操作系统层面,若主进程在子进程结束前退出,Linux内核会将子进程的父进程ID更改为1(即init进程),随后由init进程负责回收该子进程资源。
子线程在父线程退出后的状态取决于其所属进程是否存活。若进程未退出,子线程可继续运行;若进程退出,其包含的所有线程均会终止。
默认非守护线程的结束行为
标题:主线程退出后,进程等待所有子线程执行完毕才结束
进程启动时默认生成主线程,且默认创建的子线程非守护线程(setDaemon(False))。因此,主线程结束后,子线程仍会继续执行,进程会等待所有子线程完成后再退出。
所有线程共享同一终端输出(即所属进程的终端)。
import threading
import time
def child_thread1():
for i in range(100):
time.sleep(1)
print('child_thread1_running...')
def parent_thread():
print('parent_thread_running...')
thread1 = threading.Thread(target=child_thread1)
thread1.start()
print('parent_thread_exit...')
if __name__ == "__main__":
parent_thread()
代码输出示例:
parent_thread_running...
parent_thread_exit...
child_thread1_running...
child_thread1_running...
child_thread1_running...
child_thread1_running...
...
从输出可见,父线程结束后子线程仍在运行,此时若结束进程,子线程才会被终止。
守护线程对进程退出的影响
标题:主线程结束后,进程不等待守护线程完成,立即结束
当线程被设置为守护线程时,其所属进程不会等待该线程运行结束,而是立即结束进程。
import threading
import time
def child_thread1():
for i in range(100):
time.sleep(1)
print('child_thread1_running...')
def child_thread2():
for i in range(5):
time.sleep(1)
print('child_thread2_running...')
def parent_thread():
print('parent_thread_running...')
thread1 = threading.Thread(target=child_thread1)
thread2 = threading.Thread(target=child_thread2)
thread1.setDaemon(True)
thread1.start()
thread2.start()
print('parent_thread_exit...')
if __name__ == "__main__":
parent_thread()
代码输出示例:
parent_thread_running...
parent_thread_exit...
child_thread1_running...child_thread2_running...
child_thread1_running...child_thread2_running...
child_thread1_running...child_thread2_running...
child_thread1_running...child_thread2_running...
child_thread2_running...child_thread1_running...
Process finished with exit code 0
thread1设为守护线程,thread2为非守护线程。因此,进程会等待thread2完成后结束,而不等待thread1完成。
注意:子线程会继承父线程的daemon属性,即由守护线程开启的子线程仍然是守护线程。
Join方法与异常处理下的线程状态
标题:主线程等待子线程完成后结束
在线程A中调用B.join()表示线程A在调用join()处被阻塞,必须等待线程B执行完毕后才能继续执行后续代码。
import threading
import time
def child_thread1():
for i in range(10):
time.sleep(1)
print('child_thread1_running...')
def child_thread2():
for i in range(5):
time.sleep(1)
print('child_thread2_running...')
def parent_thread():
print('parent_thread_running...')
thread1 = threading.Thread(target=child_thread1)
thread2 = threading.Thread(target=child_thread2)
thread1.setDaemon(True)
thread2.setDaemon(True)
thread1.start()
thread2.start()
thread2.join()
1/0
thread1.join()
print('parent_thread_exit...')
if __name__ == "__main__":
parent_thread()
代码输出示例:
parent_thread_running...
child_thread1_running...
child_thread2_running...
child_thread1_running...
child_thread2_running...
child_thread1_running...
child_thread2_running...
child_thread1_running...
child_thread2_running...
child_thread1_running...
child_thread2_running...
Traceback (most recent call last):
File "E:/test_thread.py", line 31, in <module>
parent_thread()
File "E:/test_thread.py", line 25, in parent_thread
1/0
ZeroDivisionError: integer division or modulo by zero
主线程在执行到thread2.join()时被阻塞,直到thread2结束后才执行下一句代码。
若执行1/0会导致主线程报错退出,且thread1已设置daemon=True,因此主线程意外退出时thread1也会立即结束。此时thread1.join()未被主线程执行。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









