子进程会终止其孩子进程,但不会终止孩子进程生成的进程。

6

我一直有一个问题,即我可以杀死产生节点的进程,但节点不会被终止。有没有人有什么建议,我该怎么做?

我最近尝试解决此问题的一些失败尝试包括:

node.terminate()

并且

node.send_signal(signal.SIGINT)

以下是代码:
from subprocess import Popen
import json
import sys
import os
import signal
import requests

FNULL = open(os.devnull, 'w')

json_data = open('nodes.json', 'r').read()
data = json.loads(json_data)

port = data['port']

# launch hub
hub = Popen('java -jar selenium-server-standalone-2.37.0.jar -role hub -port %s' % port, stdout=FNULL, stderr=FNULL, shell=True)

#launch nodes
nodes = []
for node in data['nodes']:
    options = ''
    if node['name'] == 'CHROME':
        options += '-Dwebdriver.chrome.driver=../grid/chromedriver '
    #options += ' -browser browserName='+node['name']+' maxInstances='+str(node['maxInstances'])
    nodes.append(Popen('java -jar selenium-server-standalone-2.37.0.jar -role node -hub http://localhost:%i/grid/register %s' % (port, options), stdout=FNULL, stderr=FNULL, shell=True))

# wait for user input
print "type 'q' and ENTER to close the grid:"
while True:
    line = sys.stdin.readline()
    if line == 'q\n':
        break

# close nodes
for node in nodes:
    #node.terminate()
    node.send_signal(signal.SIGINT)

# close hub   
r = requests.get('http://localhost:'+str(port)+'/lifecycle-manager?action=shutdown')

据我所知,我基本上被迫使用shell=True才能使重定向起作用。在父Python进程中处理子进程的stdout/stderr不是一个选择,因为我找不到一种非等待方式来执行它的功能(并且父Python进程必须在子进程运行时执行其他任务)。
# close nodes
for node in nodes:
    node.send_signal(signal.SIGINT)
    node.terminate()    

这似乎会杀死除了一个节点之外的所有进程。而且不是总是同一个节点。


2
换句话说,调用 shell 可以为您提供一些指定参数的便利,但这也意味着在父进程和子进程之间还有另一个进程。系统 shell 可能不会将 SIGINT 传递给其子进程。 - kojiro
我怀疑@kojiro是正确的。我没有注意到你在代码中指定了“shell=True” :) - James Mills
1
这可能会有用吗?或许在这里发送“SIGTERM”而不是“SIGINT”可能会起作用?请参考此链接:https://dev59.com/HHE85IYBdhLWcg3w9onw - James Mills
1
这篇文章也许会有用,它似乎涵盖了类似的情况(即需要使用shell=True的情况)。 - Dave Challis
你想要终止哪个进程(名称),并且你想要保留哪些进程?你能否创建一个完整的最小代码示例(即使是带有虚拟子进程)来说明你的观点?不清楚你想要终止哪些进程:是shell,还是java,或者是由jvm启动的子进程? - jfs
显示剩余9条评论
1个回答

3
您可以尝试使用os.killpg。此函数向进程组发送信号,如果您的进程不更改进程组,则应该可以正常工作。
import os
import signal

os.killpg(os.getpgid(pid), signal.SIGINT)

请注意,在使用shell(bash,zsh等)创建进程时,进程组会发生变化,在这种情况下应该使用更复杂的技术。

1
os.killpg(os.getpgid(pid), signal.SIGINT) - DanJ
2
不幸的是,这也会终止调用程序。您需要在“Popen”中添加“preexec_fn = os.setsid”。 - Wes Modes

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