Python 无法通过终止父进程来终止生成的子进程

问题描述 投票:0回答:1

我有一个主脚本(Python),我想从中生成几个子脚本。子脚本应该独立运行而不会互相干扰(只是循环写入文件)。我想要什么 - 当主脚本终止时,所有生成的子进程也应该终止。

但是,即使通过

CTRL-C
杀死主进程并将控制权返回到命令提示符,子进程仍继续运行,因为我可以看到各个输出文件不断更新。关于如何使这项工作有任何想法吗?

子脚本

import sys
from time import sleep

arg = sys.argv[1]
sleepTime = int(sys.argv[2])
while True:
    with open(f"{arg}.txt", "w") as f:
        f.write(arg)
    sleep(sleepTime)

主脚本

import sys, subprocess, os, signal
from time import sleep

d = ['fool', 'gool', 'lool']
for i in range(3):
    try:
        subprocess.Popen(['python3', 'child.py', d[i], str(i + 3)], stdin=subprocess.PIPE)
    except KeyboardInterrupt:
        sys.exit(1)

我在命令行中运行什么来启动一切:

python3 master.py
python subprocess popen sigint
1个回答
0
投票

当父母终止时如何终止孩子

我不想继续发表评论,而是将其放在答案中。然而,我仍然不清楚你想做什么,因为它有点矛盾,尽管如此,这给出了答案。

这对我来说似乎矛盾的原因是因为你说你希望孩子在父母终止时终止。但是这样的话,你的孩子将没有机会做任何事情,因为父母只产生了 3 个孩子(速度非常快),然后什么也不做。于是终止。 生成子进程的全部目的是让父进程可以在生成后执行其他操作或终止。

如果你想编程让孩子在父母终止时终止,你可以这样做

import sys, subprocess, os, signal
from time import sleep
import atexit

d = ['fool', 'gool', 'lool']
pp=[]
for i in range(3):
    try:
        p=subprocess.Popen(['python3', 'child.py', d[i], str(i + 3)], stdin=subprocess.PIPE)
        pp.append(p)
    except KeyboardInterrupt:
        sys.exit(1)


def masterFinish():
    for p in pp:
        p.terminate()
    sys.exit(1)
atexit.register(masterFinish)

或者,更一致地这样

import sys, subprocess, os, signal
from time import sleep
import atexit

d = ['fool', 'gool', 'lool']
pp=[]
for i in range(3):
    p=subprocess.Popen(['python3', 'child.py', d[i], str(i + 3)], stdin=subprocess.PIPE)
    pp.append(p)

def masterFinish():
    for p in pp:
        p.terminate()
    sys.exit(1)
atexit.register(masterFinish)

由于您实际上并不需要那个 void

KeyboardInterrupt
处理程序,因此它只会在父母生成每个孩子所需的非常短的时间内执行某些操作。

但是,正如我所说,这意味着一旦父母终止,孩子就会终止。那是在第三个孩子出生之后。与此同时,即使是第一个孩子也可能仍在启动 python 解释器的过程中,并且可能没有时间运行第一行 python 代码。因此在它有机会做某事之前就终止了。

在我的机器上,它根本不创建任何文件。 Kid 1 被生成,然后是 Kid 2,然后是 Kid 3,然后它们都被终止,“master”结束。就这样。这就是你所要求的,但我怀疑这就是你想要的。

如何在孩子中使用 Ctrl-C

我的感觉是,你的“interruptHandler”应该在每个孩子的后台运行,并确保孩子在收到 ctrl-c 时终止。但事实并非如此。在后台运行的代码部分是孩子们的部分。您的处理程序是“主”代码的一部分,

因此,您应该将“中断处理程序”放在

child.py
代码中。

import sys
from time import sleep

arg = sys.argv[1]
sleepTime = int(sys.argv[2])
try:
    while True:
        with open(f"{arg}.txt", "w") as f:
            f.write(arg)
        sleep(sleepTime)
except KeyboardInterrupt:
    sys.exit(1)

这可能更接近您想要做的事情。 也许您已经尝试过,然后尝试了其他方法,因为它“不起作用”。 但确实如此。只是,孩子需要接收 Ctrl-C。但它不会,因为它们是分离的,因为主人已经完成了。

只需在

master
代码中添加任何内容,他们就会收到 ctrl-c

import sys, subprocess, os, signal
from time import sleep

d = ['fool', 'gool', 'lool']
for i in range(3):
    try:
        subprocess.Popen(['python3', 'child.py', d[i], str(i + 3)], stdin=subprocess.PIPE)
    except KeyboardInterrupt:
        sys.exit(1)

sleep(30)

然后如果你按 ctrl-c,孩子们就会退出。大师也是如此。

请注意,

master
的中断处理程序和子进程的中断处理程序在这里都没有什么用处。

  • 正如我之前所说,主控器仅在调用
    subprocess
    所需的极短时间内使用。所以在你有机会输入 ctrl-c 之前已经结束了一段时间,这很可能发生在
    sleep(30)
    期间。
  • 我添加到孩子的那个(以展示你应该如何向孩子添加中断处理程序:在他们的代码中,而不是在主人的代码中),可以工作(它将运行该处理程序的
    system.exit
    )并退出孩子),但仍然没有必要,因为无论如何这是默认行为。

另请注意,这仅涵盖 ctrl-c pat(它解释了为什么您的孩子没有收到 ctrl-c)。有了这个

sleep(30)
,因此在
master
仍在运行的30秒内,如果你输入ctrl-c,孩子们也会收到它,然后结束。

它不包括 30 秒后发生的事情。 所以,无论如何都需要我的第一个答案(atexit - 或其他方法来实现同样的事情。例如,只需在

master
代码末尾终止孩子)

import sys
from time import sleep

arg = sys.argv[1]
sleepTime = int(sys.argv[2])
while True:
    with open(f"{arg}.txt", "w") as f:
        f.write(arg)
    sleep(sleepTime)
import sys, subprocess, os, signal
from time import sleep

d = ['fool', 'gool', 'lool']
pp=[]
for i in range(3):
    p=subprocess.Popen(['python3', 'child.py', d[i], str(i + 3)], stdin=subprocess.PIPE)
    pp.append(p)

sleep(30) # or do something else

for p in pp: p.terminate()

在最后一个示例中,如果没有 void 中断处理程序,无论是在主机中还是在子程序中,当主机与子程序在后台运行时,主机和子程序都会在 30 秒内收到 ctrl-c。并会以默认行为做出反应,即终止。

然后,在 30 秒结束后(或者 master 在子进程工作时所做的任何其他事情),master 结束,并在结束之前结束其子进程。

© www.soinside.com 2019 - 2024. All rights reserved.