Python线程/守护进程

Python线程/守护进程,python,multithreading,daemon,Python,Multithreading,Daemon,自学编程的学生,所以我为所有的业余错误道歉。我想学习一些更深层次的课程,所以我试图理解线程和异常处理 import threading import sys from time import sleep from random import randint as r def waiter(n): print "Starting thread " + str(n) wait_time = r(1,10) sleep(wait_time) print "Exitin

自学编程的学生,所以我为所有的业余错误道歉。我想学习一些更深层次的课程,所以我试图理解线程和异常处理

import threading
import sys
from time import sleep
from random import randint as r

def waiter(n):
    print "Starting thread " + str(n)
    wait_time = r(1,10)
    sleep(wait_time)
    print "Exiting thread " + str(n)

if __name__=='__main__':
    try:
        for i in range(5):
            t = threading.Thread(target=waiter, args=(i+1,))
            t.daemon = True
            t.start()
            sleep(3)
        print 'All threads complete!'
        sys.exit(1)
    except KeyboardInterrupt:
        print ''
        sys.exit(1)
此脚本只是在一段随机时间后启动和停止线程,如果收到
^C
,它将终止程序。我注意到,当某些线程完成时,它不会打印:

Starting thread 1
Starting thread 2
Starting thread 3
Exiting thread 3
Exiting thread 2
Starting thread 4
Exiting thread 1
Exiting thread 4
Starting thread 5
All threads complete!
在本例中,它从未声明退出线程5。如果我注释掉
t.daemon=True
语句,我发现我可以解决这个问题,但是异常处理会等待任何线程完成

Starting thread 1
Starting thread 2
^C
Exiting thread 1
Exiting thread 2
我可以理解,在处理线程时,最好在退出之前完成正在处理的任务,但我只是好奇为什么会这样。如果您能回答有关线程和守护进程性质的问题,以指导我的理解,我将不胜感激。

守护进程线程的全部要点是,如果在主线程完成时它还没有完成,它将立即被杀死。引述:

线程可以标记为“守护线程”。此标志的意义在于,当只剩下守护进程线程时,整个Python程序将退出。初始值从创建线程继承。可以通过daemon属性或daemon构造函数参数设置该标志

注意:守护进程线程在关机时突然停止。他们的资源(如打开的文件、数据库事务等)可能无法正常释放。如果希望线程正常停止,请将其设为非守护线程,并使用适当的信号机制,如事件

现在,看看你的逻辑。主线程在启动线程5后只休眠3秒钟。但是线程5可以在任何地方休眠1-10秒。因此,大约70%的时间,当主线程醒来,打印“所有线程完成!”并退出时,它不会完成。但线程5仍在休眠5秒钟。在这种情况下,线程5将被终止,而不会打印“退出线程5”


如果这不是您想要的行为如果您想要主线程等待所有线程完成,那么不要使用守护线程。

我明白了,这是有道理的。因此,我假设任何处理关键和敏感数据的线程(即,不应突然终止的线程)都不应标记为守护进程线程?@dbishop:一般来说,是的。但是,如果您的敏感数据处理线程可以“在一边”成批完成其工作,然后以原子方式提交每一项工作(例如,写入临时文件,然后将该临时文件移动到永久位置),则可以安全地将其杀死。@dbishop:,可以使用同步机制让主线程向工作人员发出信号,告诉他们该关机了,给他们一些时间让他们全部响应,只有在他们响应不够快的情况下才进行解救并让他们被杀死。这种设计对于需要“相当可靠”但不是100%的东西来说很常见,比如web服务器连接处理程序。明白了。我想我现在明白多了。谢谢你的帮助!非常感谢!我怀疑您实际上在寻找一种方法,使线程的行为与普通线程类似,但在您真正需要时(例如,如果用户迫切需要^C应用程序),可以像守护进程线程一样异步终止线程,对吗?这很难做到,但并非不可能。@abarnert这不是我最初想要做的,但现在你提到了,我想看看如何做到。我现在真的不需要这些知识(不是编写任何重要的或有价值的脚本),我只是想发展一种理解,因为我喜欢这类事情:)例如:使用守护进程线程,但假装在大多数代码中没有。通过等待所有工人向您发出他们已经完成的信号(使用一些同步对象)退出。提前退出通知他们所有人退出(注意,这意味着您需要重构工人,以便他们定期检查标志和同步对象),然后等待他们。通过向他们发送信号,等待他们超时,然后退出(这意味着他们几乎总是需要在该超时内检查标志),尽早快速退出。尽早退出,立即退出。@abarnert。。。好吧,我相信我现在的做法会很好,谢谢你的解释。大部分我都不懂,但5年后,当我真的从某个地方学到这些东西时,我会回顾你的评论并想,“啊,是的,我是多么愚蠢。”或者,如果我们仍然在低级别(线程和同步对象)编写并发代码,那么它将适用于具有16个完整内核、256个微内核的大规模非统一系统,还有数千个SIMD频道和GPU通道,我今天所知道的一切都将大错特错