0

我有以下问题:

我需要我的 Python 脚本运行一个 bash 脚本。如果 bash 脚本运行时间超过 10 秒,我需要终止它。这是我到目前为止所拥有的:

cmd = ["bash", "script.sh", self.get_script_path()]
process = subprocess.Popen(cmd)

time.sleep(10)  # process running here...

procinfo = psutil.Process(process.pid)
children = procinfo.children(recursive=True)
for child in children:
    os.kill(child.pid, signal.SIGKILL)

我害怕的是这种情况:bash 脚本在 1 秒内完成,释放它的 PID,系统将 PID 传递给另一个进程。10 秒后,我杀死了我认为属于我的脚本的 PID,但事实并非如此,我杀死了其他一些进程。该脚本需要以 root 身份运行,因为我需要chroot它。

有任何想法吗?

4

3 回答 3

2

由于您已经在使用,psutil我建议您将subprocess模块调用替换为对psutil.Popen. 此类具有与 相同的接口,subprocess.Popen但提供了所有功能psutil.Process

另请注意,psutil库已预先检查 PID 重用,至少对于包括terminateand在内的许多方法kill(只需阅读文档Process)。

这意味着以下代码:

cmd = ["bash", "script.sh", self.get_script_path()]
process = psutil.Popen(cmd)

time.sleep(10)  # process running here...

children = process.children(recursive=True)
for child in children:
    child.terminate()   # try to close the process "gently" first
    child.kill()

请注意,文档children说:

孩子(递归=假)

将该进程的子进程作为Process对象列表返回,抢先检查 PID 是否已被重用。

总之,这意味着:

  1. 当您调用库时childrenpsutil检查您是否想要正确进程的子进程,而不是碰巧具有相同 pid 的子进程
  2. 当您调用terminatekill库确保您正在杀死您的子进程而不是具有相同 pid 的随机进程时。
于 2016-08-28T08:15:52.667 回答
0

我认为该timeout命令非常适合您。从文档页面:

概要

超时 [选项] 数字 [后缀] 命令 [ARG] ...
超时 [选项]


描述

启动 COMMAND,如果在 NUMBER 秒后仍在运行,则将其终止。SUFFIX 可以是 's' 秒(默认值),'m' 分钟,'h' 小时或 'd' 天。

-s , --signal = SIGNAL
指定超时发送的信号。
        SIGNAL可以是一个名称,如“HUP”或一个数字。
        有关信号列表,请参见“kill -l”

通过依赖timeout,您不必担心 PID 重用、竞争条件等杂乱的细节。这些问题很好地封装在这个标准的 Unix 实用程序中。另一个好处是您的脚本将在子进程提前终止后立即恢复执行,而不是不必要地休眠整整 10 秒。

bash 中的演示:

timeout -s9 10 sleep 11; echo $?;
## Killed
## 137
timeout -s9 10 sleep 3; echo $?;
## 0

python中的演示:

import subprocess;
subprocess.Popen(['timeout','-s9','10','sleep','11']).wait();
## -9
subprocess.Popen(['timeout','-s9','10','sleep','3']).wait();
## 0
于 2016-08-28T08:03:28.830 回答
-3

我在 ubuntu 上使用命令 stop process_name 来停止我的进程。愿它会有所帮助。

于 2016-08-28T07:19:54.707 回答