在我知道的所有实现(C Python、PyPy 和 Jython)中,Python 线程都是使用操作系统线程实现的。对于每个 Python 线程,都有一个底层 OS 线程。
某些操作系统(Linux 就是其中之一)在所有正在运行的进程列表中显示由同一可执行文件启动的所有不同线程。这是操作系统的实现细节,而不是 Python 的实现细节。在其他一些操作系统上,列出所有进程时您可能看不到这些线程。
当最后一个非守护线程完成时,进程将终止。此时,所有守护线程都将被终止。因此,这些线程是您进程的一部分,但不会阻止它终止(而常规线程会阻止它)。这是用纯 Python 实现的。当调用系统_exit 函数时进程终止(它将杀死所有线程),并且当主线程终止(或调用sys.exit)时,Python 解释器检查是否有另一个非守护线程正在运行。如果没有,则调用_exit,否则等待非守护线程完成。
守护线程标志由threading 模块在纯Python 中实现。加载模块时,会创建一个Thread对象来表示主线程,并将其_exitfunc方法注册为atexit钩子。
这个函数的代码是:
class _MainThread(Thread):
def _exitfunc(self):
self._Thread__stop()
t = _pickSomeNonDaemonThread()
if t:
if __debug__:
self._note("%s: waiting for other threads", self)
while t:
t.join()
t = _pickSomeNonDaemonThread()
if __debug__:
self._note("%s: exiting", self)
self._Thread__delete()
当sys.exit 被调用或主线程终止时,Python 解释器将调用该函数。当函数返回时,解释器会调用系统_exit函数。当只有守护线程在运行(如果有)时,函数将终止。
当_exit函数被调用时,操作系统会终止所有进程线程,然后终止进程。在所有非守护线程完成之前,Python 运行时不会调用_exit 函数。
所有线程都是进程的一部分。
我的解释/理解是:主线程在所有
非守护线程被终止。
所以如果“整个
只剩下守护线程时Python程序退出”?
你的理解不正确。对于OS来说,一个进程是由很多线程组成的,所有线程都是相等的(对于OS来说,主线程没什么特别的,只是C运行时在main的末尾添加了对_exit的调用功能)。并且操作系统不知道守护线程。这纯粹是一个 Python 概念。
Python 解释器使用原生线程来实现 Python 线程,但必须记住创建的线程列表。并且使用它的atexit 钩子,它确保_exit 函数仅在最后一个非守护线程终止时返回到操作系统。使用“整个 Python 程序”时,文档指的是整个过程。
下面的程序可以帮助理解守护线程和普通线程的区别:
import sys
import time
import threading
class WorkerThread(threading.Thread):
def run(self):
while True:
print 'Working hard'
time.sleep(0.5)
def main(args):
use_daemon = False
for arg in args:
if arg == '--use_daemon':
use_daemon = True
worker = WorkerThread()
worker.setDaemon(use_daemon)
worker.start()
time.sleep(1)
sys.exit(0)
if __name__ == '__main__':
main(sys.argv[1:])
如果您使用“--use_daemon”执行此程序,您将看到该程序将仅打印少量Working hard 行。如果没有这个标志,即使主线程结束,程序也不会终止,程序将打印Working hard行,直到它被杀死。