Does Daemon Thread Exit with Main Thread?
主线程(进程)退出后,主线程创建的守护线程也会退出吗?
通过下面的代码测试:
Demo1: 进程创建普通线程
#!/usr/bin/python3 # FileName: daemonThread.py # Author: lxw # Date: 2016-02-25 import threading import time def show(num): time.sleep(3) print("In show(): {0}".format(num)) with open("/home/lxw/Documents/NOTE", "w") as f: f.write("hello") def main(): th = threading.Thread(target=show, args=(1,)) #th.setDaemon(True) th.start() print("main() over. Program exit!") if __name__ == '__main__': main() else: print("Being imported as a module.")
运行结果:
lxw Documents$ python3 daemonThread.py main() over. Program exit! In show(): 1 lxw Documents$
"The entire Python program exits when no alive non-daemon threads are left".
只有当前进程的所有非守护线程 全部结束后,当前进程才能结束。
Demo2: 进程创建守护线程
#!/usr/bin/python3 # FileName: daemonThread.py # Author: lxw # Date: 2016-02-25 import threading import time def show(num): time.sleep(3) print("In show(): {0}".format(num)) with open("/home/lxw/Documents/NOTE", "w") as f: f.write("hello") def main(): th = threading.Thread(target=show, args=(1,)) th.setDaemon(True) th.start() print("main() over. Program exit!") if __name__ == '__main__': main() else: print("Being imported as a module.")
运行结果:
lxw Documents$ ls daemonThread.py NOTE ThreadPool_Python lxw Documents$ rm NOTE lxw Documents$ ls daemonThread.py ThreadPool_Python lxw Documents$ python3 daemonThread.py main() over. Program exit! lxw Documents$ ls daemonThread.py ThreadPool_Python
从运行结果我们可以看到,当前进程的守护线程 并没有结束,但当前进程仍然可以退出。并且当前进程结束后,该进程的守护线程也会结束,不会继续运行。
也就是说进程退出并不考虑守护线程,只考虑非守护线程。
通过这两段代码的验证,我们可以得出本文标题的答案:进程结束后,该进程的守护线程也会结束,不会继续运行。
Reference:
1. [Java基础] java的守护线程与非守护线程 虽然这篇文章讲的是Java的,但和Python也是通用的。
守护线程并非虚拟机内部可以提供,用户也可以自行的设定守护线程,方法:public final void setDaemon(boolean on) ;但是有几点需要注意:
1). thread.setDaemon(true)必须在thread.start()之前设置,否则会跑出一个 IllegalThreadStateException异常。你不能把正在运行的常规线程设置为守护线程。(备注:这点与守护进程有着明显的区别, 守护进程是创建后,让进程摆脱原会话的控制+让进程摆脱原进程组的控制+让进程摆脱原控制终端的控制;所以说寄托于虚拟机的语言机制跟系统级语言有着本质上面的区别)
2). 在Daemon线程中产生的新线程也是Daemon的。(这一点又是有着本质的区别了:守护进程fork()出来的子进程不再是守护进程,尽管它把父进程的进程相关信息复制过去了,但是子进程的进程的父进程不是init进程,所谓的守护进程本质上说就是“父进程挂掉,init收养,然后 文件0,1,2都是/dev/null,当前目录到/”)
2. 这篇博文的评论