检查进程是否仍然 运行

Check if a process is still running

我遇到以下问题:

我需要我的 Python 脚本 运行 一个 bash 脚本。如果 bash 脚本 运行ning 超过 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 在其中。

有什么想法吗?

我在 ubuntu 上使用命令停止 process_name 来停止我的进程。 希望对你有帮助。

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

Synopsis

timeout [OPTION] NUMBER[SUFFIX] COMMAND [ARG]...
timeout [OPTION]


Description

Start COMMAND, and kill it if still running after NUMBER seconds. SUFFIX may be 's' for seconds (the default), 'm' for minutes, 'h' for hours or 'd' for days.

-s, --signal=SIGNAL
specify the signal to be sent on timeout.
        SIGNAL may be a name like 'HUP' or a number.
        See 'kill -l' for a list of signals

通过依赖 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

由于您已经在使用 psutil,我建议您将对 subprocess 模块的调用替换为对 psutil.Popen 的调用。此 class 具有与 subprocess.Popen 相同的界面,但提供 psutil.Process.

的所有功能

另请注意,psutil 库已经先发制人地检查 PID 重用 ,至少对于包括 terminatekill(只需阅读 documentation for 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 的文档说:

children(recursive=False)

Return the children of this process as a list of Process objects, preemptively checking whether PID has been reused.

总而言之,这意味着:

  1. 当您调用 children 时,psutil 库会检查您是否需要正确进程的子进程,而不是碰巧具有相同 pid 的子进程
  2. 当您调用 terminatekill 时,库会确保您终止的是您的子进程,而不是具有相同 pid 的随机进程。