【问题标题】:Check if a process is still running检查进程是否仍在运行
【发布时间】:2016-08-28 07:16:43
【问题描述】:

我有以下问题:

我需要我的 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

有什么想法吗?

【问题讨论】:

  • 如果子进程是在没有shell=True 的情况下创建的,那么您应该能够简单地使用process.kill()。否则请参考this question

标签: python linux bash process psutil


【解决方案1】:

由于您已经在使用psutil,我建议您将对subprocess 模块的调用替换为对psutil.Popen 的调用。该类与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 的文档说:

儿童(recursive=False)

Process对象列表的形式返回这个进程的子进程,抢先检查PID是否被重用。

总而言之,这意味着:

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

【讨论】:

    【解决方案2】:

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

    概要

    超时 [OPTION] NUMBER[SUFFIX] COMMAND [ARG]...
    超时 [OPTION]


    说明

    启动 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
    

    【讨论】:

    • 谢谢,这可能有用。在这种情况下,我更喜欢原生 python 解决方案。无论如何感谢timeout的介绍:)
    【解决方案3】:

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

    【讨论】:

    • 抱歉,我需要一个适用于所有 linux 发行版的解决方案。我说脚本是以root身份运行的,所以我这里的sudo不明白。最后,进程名称是 bash,所以我不能按名称杀死它。
    猜你喜欢
    • 2011-03-07
    • 2013-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-02
    • 2012-07-10
    相关资源
    最近更新 更多