小编典典

什么是python线程

python

我对Python线程有几个疑问。

  1. Python线程是Python还是OS实现?
  2. 当我使用htop时,多线程脚本具有多个条目-相同的内存消耗,相同的命令但不同的PID。这是否意味着[Python]线程实际上是一种特殊的过程?(我知道htop中有一个设置将这些线程显示为一个进程- Hide userland threads
  3. 文档说:

线程可以标记为“守护程序线程”。该标志的重要性在于,仅保留守护程序线程时,整个Python程序都会退出。

我的解释/理解是:当所有非守护程序线程终止时,主线程终止。

那么,如果“仅保留守护程序线程时整个Python程序退出”,那么python守护程序线程就不属于Python程序?


阅读 210

收藏
2020-12-20

共1个答案

小编典典

  1. 在我所知道的所有实现中(C Python,PyPy和Jython),都使用OS线程来实现Python线程。对于每个Python线程,都有一个底层的OS线程。

  2. 某些操作系统(Linux是其中之一)在所有正在运行的进程的列表中显示了同一可执行文件启动的所有不同线程。这是操作系统的实现细节,而不是Python的实现细节。在某些其他操作系统上,列出所有进程时可能看不到那些线程。

  3. 最后一个非守护线程完成时,该过程将终止。届时,所有守护程序线程将终止。因此,这些线程是您进程的一部分,但并不能阻止它终止(而常规线程可以阻止它终止)。那是用纯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调用该函数时,操作系统将终止所有进程线程,然后终止进程。在_exit所有非守护程序线程完成之前,Python运行时不会调用该函数。

所有线程都是该过程的一部分。


我的解释/理解是:当所有非守护程序线程终止时,主线程终止。

因此,如果“仅保留守护程序线程时整个Python程序退出”,那么python守护程序线程就不属于python程序?

您的理解不正确。对于OS,一个进程由许多线程组成,所有线程都是相同的(对于OS的主线程,没有什么特别的,除了C运行时_exitmain函数末尾添加了对它的调用)。而且操作系统不知道守护线程。这纯粹是一个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行直到被杀死。

2020-12-20