为什么在python中主进程退出时子进程(daemon=True)不退出?

为什么在python中主进程退出时子进程(daemon=True)不退出?,python,process,daemon,Python,Process,Daemon,以下是python多处理中守护进程标志的官方解释: 当进程退出时,它会尝试终止其所有daemonic子进程 据我所知,父进程将在退出时杀死其守护进程标志设置为True的子进程 下面是我用来证明我猜测的代码。但结果是不同的 import multiprocessing def child(): while True: pass for x in xrange(1, 4): proc = multiprocessing.Process(target=child

以下是python多处理中
守护进程
标志的官方解释:

当进程退出时,它会尝试终止其所有daemonic子进程

据我所知,父进程将在退出时杀死其守护进程标志设置为True的子进程

下面是我用来证明我猜测的代码。但结果是不同的

import multiprocessing


def child():
    while True:
        pass


for x in xrange(1, 4):
    proc = multiprocessing.Process(target=child, args=())
    proc.daemon=True
    proc.start()


while True:
    pass
上面启动4个子进程和一个主进程。 我杀死了主进程,但4个孩子没有退出


既然守护进程被设置为true,为什么它们不被main终止呢?

是的,您的理解是正确的,您的测试代码也可以

我刚刚添加了一些sleep语句来调试输出(如果没有
sleep
,很难从大量打印输出中推断):

现在,当我运行这个脚本时,当它运行时,我做了一个
ps aux
,可以看到四个进程从这个脚本运行。7秒钟后,当我再次执行
ps aux
时,我再也看不到这些进程正在运行-这意味着:

当主进程退出时,它终止了所有守护进程

之后,我还将
proc.daemon
设置为
False
,并再次运行脚本。这一次,即使在7秒钟之后,当我执行
ps aux
时,我仍然可以看到子进程正在运行(因为它们现在是非守护进程,即使主进程终止,它们也不会退出)

因此,这是预期的工作-让我知道,如果你仍然有一个问题在这里

编辑1: 感谢@CristiFati指出最初的清理问题。
此代码之所以有效,是因为调用
sys.exit()
也会按照详细说明注册
atexit
回调。

注意:

  • xrange的使用意味着Python 2
  • xrange(1,4)
    将产生3个值,而不是4个值(因此,只有3个子项)
事情并非如此。doc()应该更具体一些

问题是,多处理注册了一个清理函数,以在退出时杀死其所有deamonic子级。这是通过以下方式实现的:

注意:当程序被Python未处理的信号终止时,当检测到Python致命内部错误时,或当调用时,不会调用通过此模块注册的函数

您不处理术语信号(默认情况下由kill命令发送),因此主进程不调用cleanup函数(保持其子进程运行)

我修改了您的代码以更好地说明该行为

代码00.py:

#/usr/bin/env蟒蛇2
导入系统
导入多处理
导入操作系统
导入时间
print_text_pattern=“进程{0:s}的输出-pid:{1:d},ppid:{2:d}”
def子项(名称):
尽管如此:
打印(打印文本模式格式(名称,os.getpid(),os.getppid())
时间。睡眠(1)
def main():
procs=list()
对于x范围内的x(1,3):
proc_name=“Child{0:d}”。格式(x)
proc=multiprocessing.Process(target=child,args=(proc\u name,))
proc.daemon=True#x%2==0
打印(“进程{0:s}守护进程:{1:}”。格式(进程名称,进程守护进程))
过程追加(proc)
对于进程中的进程:
程序启动()
计数器=0
当计数器<3时:
打印(打印文本格式(“Main”、os.getpid()、os.getppid()))
时间。睡眠(1)
计数器+=1
如果名称=“\uuuuu main\uuuuuuuu”:
打印(“Python{0:s}{1:d}位在{2:s}\n.format(“.join(sys.version.split(“\n”)中的项的item.strip()),如果sys.maxsize>0x100000000,则为64,否则为32,sys.platform))
main()
打印(“\n完成”)

注释

  • 稍微改变了生成子进程的方式:首先创建所有子进程,然后才开始
  • 添加了来自每个进程的一些打印调用,以跟踪它们在stdout中的活动-还添加了一些
    time.sleep
    调用(1秒),以避免产生太多的输出
  • 最重要的-主流程不再永远运行。在某个点上,它会优雅地退出(在3个循环之后——由于计数器变量),而我前面提到的行为也会在这个点上开始
    这也可以通过截取术语信号(以及其他可以通过kill命令显式发送的信号)并执行清理来实现——这样在杀死主进程时也会杀死子进程——但这更复杂
  • 我把事情简化了一点,只生了两个孩子
  • 移动了包含在
    中的主函数(用于结构)中的所有内容(如果
    中的名称条件,因此如果导入
    模块,则不会生成进程
  • 为每个子级指定不同的值
    proc.daemon
    ,然后监视输出和
    ps-ef | grep“code00.py”
    输出
  • 向子func添加了一个参数(名称),但这仅用于显示目的
输出

[cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow]>python2代码00.py
Python 2.7.12(默认值,2019年10月8日,14:14:10)[GCC 5.4.0 20160609]linux2上的64位
进程Child1守护进程:True
进程Child2守护进程:True
工艺主管道的输出-pid:1433,ppid:1209
来自进程Child1的输出-pid:1434,ppid:1433
来自过程Child2的输出-pid:1435,ppid:1433
工艺主管道的输出-pid:1433,ppid:1209
来自过程Child2的输出-pid:1435,ppid:1433
来自进程Child1的输出-pid:1434,ppid:1433
工艺主管道的输出-pid:1433,ppid:1209
来自进程Child1的输出-pid:1434,ppid:1433
来自过程Child2的输出-pid:1435,ppid:1433
来自进程Child1的输出-pid:1434,ppid:1433
来自过程Child2的输出-pid:1435,ppid:1433
完成。

你在哪个操作系统上?当我试着打开窗户时
import multiprocessing
import time
import sys

print("main")

def child():
    while True:
        print("child")
        time.sleep(3)

for x in xrange(1, 4):
    proc = multiprocessing.Process(target=child, args=())
    proc.daemon=True
    proc.start()

time.sleep(7)
print("exit")
sys.exit() # this exits the main process