首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >什么是python线程?

什么是python线程?
EN

Stack Overflow用户
提问于 2011-12-24 08:37:47
回答 4查看 11.3K关注 0票数 44

我有几个关于Python线程的问题。

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

可以将线程标记为“守护进程线程”。此标志的意义在于,当只剩下守护进程线程时,整个Python程序就会退出。

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

那么,如果“整个python程序在只剩下守护进程线程时退出”,Python守护进程线程就不是Python程序的一部分?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2011-12-24 08:57:53

  1. Python线程是在我所知道的所有实现(C Python、PyPy和Jython)中使用OS线程实现的。对于每个Python线程,都有一个底层OS线程。
  2. 一些操作系统(Linux就是其中之一)在所有正在运行的进程列表中显示由同一个可执行文件启动的所有不同线程。这是操作系统的实现细节,而不是Python的实现细节。在其他操作系统上,当列出所有进程时,您可能看不到这些线程。
  3. 进程将在最后一个非守护进程线程结束时终止。此时,所有守护进程线程都将终止。因此,这些线程是进程的一部分,但并不阻止它终止(而常规线程将阻止它)。这是用纯Python实现的。当调用系统_exit函数(它将杀死所有线程)和主线程终止(或调用sys.exit )时,Python解释器将检查是否有另一个非守护进程线程正在运行。如果没有,则调用_exit,否则它将等待非守护进程线程完成。

守护进程线程标志是由threading模块用纯Python实现的。加载模块时,创建一个Thread对象来表示主线程,并将其_exitfunc方法注册为atexit钩子。

此功能的代码是:

代码语言:javascript
运行
复制
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函数的末尾添加了对main的调用)。而且操作系统不知道守护进程线程。这是一个纯粹的Python概念。

Python解释器使用本机线程实现Python线程,但必须记住创建的线程列表。使用它的atexit钩子,它确保只有当最后一个非守护进程线程终止时,_exit函数才返回到操作系统。当使用“整个Python程序”时,文档指的是整个过程。

以下程序可以帮助理解守护进程线程和常规线程之间的区别:

代码语言:javascript
运行
复制
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行,直到它被杀死为止。

票数 40
EN

Stack Overflow用户

发布于 2011-12-24 09:10:03

我对实现不太熟悉,所以让我们做一个实验:

代码语言:javascript
运行
复制
import threading
import time

def target():
    while True:
        print 'Thread working...'
        time.sleep(5)

NUM_THREADS = 5

for i in range(NUM_THREADS):
    thread = threading.Thread(target=target)
    thread.start()
  1. 使用ps -o cmd,nlwp <pid>报告的线程数是NUM_THREADS+1 (主线程多一个),因此只要OS工具检测到线程数,它们就应该是OS线程。我尝试了cpython和jython,尽管在jython中还有一些其他线程正在运行,对于我添加的每一个额外线程,ps都会将线程计数增加一个。
  2. 我不确定htop的行为,但ps似乎是一致的。
  3. 在启动线程之前,我添加了以下行: thread.daemon =真 当我执行使用cpython时,程序几乎立即终止,并且没有使用ps找到任何进程,因此我的猜测是程序与线程一起结束。在jython中,程序以相同的方式工作(它没有终止),所以可能还有来自jvm的其他线程阻止程序终止或不支持守护进程线程。

注意:我在2.7.2+和java1.6.0_23上使用了Ubuntu11.10和jython2.2.1

票数 15
EN

Stack Overflow用户

发布于 2011-12-24 08:58:09

  1. Python线程实际上是一个解释器实现,因为所谓的全局解释器锁(GIL),即使在技术上使用os级线程机制也是如此。在*nix上,它正在利用线程,但是GIL有效地使它成为应用程序级线程范例的混合体。因此,您将在*nix系统上多次在ps/top输出中看到它,但它的行为(性能方面)仍然像一个软件实现的线程。
  2. 不,您只是看到了操作系统的底层线程实现。这种行为是由*nix线程样线程暴露的,或者im告诉即使windows也是这样实现线程的。
  3. 当程序关闭时,它将等待所有线程也完成。如果您有线程,可能会不确定地推迟退出,那么明智的做法是将这些线程标记为“守护进程”,并允许您的程序完成,即使这些线程仍在运行。

一些你可能感兴趣的参考资料:

  • Linux公报:理解Python中的线程
  • Doug : Python中的多处理技术
  • David : PyCon 2010:理解Python (视频演示)
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8623573

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档