从Python中终止子进程及其子进程
我在使用Python 2.5的subprocess模块来启动一个Java程序(具体来说是selenium服务器),代码如下:
import os
import subprocess
display = 0
log_file_path = "/tmp/selenium_log.txt"
selenium_port = 4455
selenium_folder_path = "/wherever/selenium/lies"
env = os.environ
env["DISPLAY"] = ":%d.0" % display
command = ["java",
"-server",
"-jar",
'selenium-server.jar',
"-port %d" % selenium_port]
log = open(log_file_path, 'a')
comm = ' '.join(command)
selenium_server_process = subprocess.Popen(comm,
cwd=selenium_folder_path,
stdout=log,
stderr=log,
env=env,
shell=True)
这个进程应该在自动化测试完成后被终止。我用os.kill
来实现这个:
os.killpg(selenium_server_process.pid, signal.SIGTERM)
selenium_server_process.wait()
但是这样并不奏效。原因是,shell子进程又启动了一个Java进程,而这个Java进程的ID在我的Python代码中是未知的。我试过用os.killpg
来杀掉进程组,但这样会把运行这段代码的Python进程也杀掉。此外,由于其他原因,我也不能把shell设置为false,这样就避免了Java在shell环境中运行。
那么,我该如何终止shell和它生成的其他进程呢?
2 个回答
4
在这种情况下,显而易见的解决办法是不使用shell:
import os
import subprocess
display = 0
log_file_path = "/tmp/selenium_log.txt"
selenium_port = 4455
selenium_folder_path = "/wherever/selenium/lies"
env = os.environ
env["DISPLAY"] = ":%d.0" % display
command = ["java",
"-server",
"-jar",
'selenium-server.jar',
"-port",
str(selenium_port)]
log = open(log_file_path, 'a')
selenium_server_process = subprocess.Popen(command,
cwd=selenium_folder_path,
stdout=log,
stderr=subprocess.STDOUT,
env=env)
这样做会让这个过程直接变成Java进程。需要注意的是,它可能仍然会启动一些不在进程组中的进程,所以使用os.killpg可能仍然无法杀掉它们。
如果你有理由需要调用shell(上面的代码并不需要,实际上有很少的事情是你不能在没有shell的情况下完成的,但假设你确实需要),那么你就得想办法让shell把它启动的进程的pid(进程ID)传给你。这样做并不简单,而且情况也比较特殊。
34
要解决这个普遍的问题:
p=subprocess.Popen(your_command, preexec_fn=os.setsid)
os.killpg(os.getpgid(p.pid), signal.SIGTERM)
setsid
这个命令会让程序在一个新的会话中运行,这样就给它和它的子进程分配了一个新的进程组。这样,当你用 os.killpg
去结束这个进程组时,就不会影响到你自己正在运行的 Python 进程了。