Python守护线程在父线程退出时不会退出

12

我有一些创建守护线程的 Python 代码。父线程几乎立即结束,但守护线程仍然继续打印“sleep”。

import threading
import time
def int_sleep():
    for _ in range(1, 600):
        time.sleep(1)
        print("sleep")

def main():
    thread = threading.Thread(target=int_sleep)
    thread.daemon = True
    thread.start()
    time.sleep(2)
    print("main thread end...")

thread = threading.Thread(target=main)
thread.start()

sys.version:

'3.3.3 (v3.3.3:c3896275c0f6, Nov 18 2013, 21:19:30) [MSC v.1600 64 bit (AMD64)]'

输出:

sleep

main thread end...

sleep

sleep

sleep

为什么当父线程退出时,Python守护线程没有退出?


请查看线程的守护进程设置.. https://dev59.com/7G855IYBdhLWcg3wc0Dy - demented hedgehog
3个回答

9
如果您为Python线程指定了thread.daemon = True,当只剩下守护进程时,程序将立即停止。此时发送到标准输出的命令将会丢失。
请将以下内容添加到名为main.py的文件中。
import threading
import time

def int_sleep():
  for _ in range(1, 600):
    time.sleep(1)
    print("sleep")

def main():
  thread = threading.Thread(target=int_sleep)
  thread.daemon = True
  thread.start()
  time.sleep(2)
  print("main thread end...")

thread = threading.Thread(target=main)
thread.daemon = True
thread.start()

像这样运行:

el@apollo:~/code/python/run01$ python --version
Python 2.7.6
el@apollo:~$ python main.py 
el@apollo:~$

看到它没有打印任何东西,因为线程已经启动。你将其设置为守护进程并启动了它。然后程序就结束了。

额外的说明:如果你将这段代码粘贴到Python解释器中,所有的打印语句都会出现在终端上,因为守护进程永远不会失去对标准输出的连接。

阅读更多:http://docs.python.org/2/library/threading.html


1
为什么我们也要将主线程设置为守护线程?如果我实现了这样的脚本...如果有一个线程在执行中卡住了,那么所有线程(包括守护线程)会在2秒的睡眠计时器后终止吗? - user3388884
这是因为你将它粘贴到终端而不是作为程序运行,我在上面解释了这种现象。 - Eric Leschinski
3
这个答案中提供的额外代码是误导性的,对于原问题的真正答案是在Python解释器中运行会产生非预期行为,而作为脚本运行则会产生预期行为。 - Johnus

5
我只能重现由OP描述的行为(“sleep”的输出不断)如果在Python shell中完成。如果从文件运行,则按预期工作(几行“sleep”和单行“main thread end ...”)。同样,第二个程序如果作为文件运行将立即退出,但是如果从Python shell运行,它还会打印无休止的“sleep”语句。我的结论是:由于作为Python shell的线程即使在“main”完成后仍然继续运行,因此当从Python shell运行时,守护程序无法被终止。这是否可以被认为是一个错误(即Python的行为因脚本运行方式而异)或者是预期的?我听取更有经验的Python专家们的建议...顺便说一下 - 在Python 3.2.3上进行测试。

4
请查看此文章以获得完整信息。 https://joeshaw.org/2009/02/24/605/

The monitoring was done inside a daemon thread. The Python docs say only:

A thread can be flagged as a “daemon thread”. The significance
of this flag is that the entire Python program exits when only
daemon threads are left.

Which sounds pretty good, right? This thread is just occasionally grabbing some data, and we don’t need to do anything special when the program shuts down. Yeah, I remember when I used to believe in things too.

Despite a global interpreter lock that prevents Python from being truly concurrent anyway, there is a very real possibility that the daemon threads can still execute after the Python runtime has started its own tear-down process. One step of this process appears to be to set the values inside globals() to None, meaning that any module resolution results in an AttributeError attempting to dereference NoneType. Other variations on this cause TypeError to be thrown.

我不确定那是一个已修复的错误还是仍然存在的错误或者是设计上的行为。但如果你看到奇怪的情况,请将其记在心里。
因此,另一种方法是在子线程中循环检查退出标志,当你完成时可以在主线程中设置该标志。然后等待子线程死亡,再进行清理。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接