在我知道的所有实现中(C Python、PyPy 和 Jython),Python 线程都是使用 OS 线程实现的。对于每个 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程序退出”意味着Python守护线程不是Python程序的一部分吗?
你的理解是错误的。对于操作系统而言,一个进程由许多线程组成,所有线程都是平等的(除了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”行,直到被杀死。
threading.Thread
对吗? - David Heffernanthread
模块提供了另一种接口来使用本地线程(但它们使用相同的本地实现)。 - Sylvain Defresne