运行一个进程,如果一个小时内不结束就杀死它

28 投票
5 回答
42904 浏览
提问于 2025-04-15 13:59

我需要在Python中做以下事情。我想要启动一个进程(可以用subprocess模块),并且:

  • 如果这个进程正常结束,就从它结束的那一刻继续执行;
  • 如果这个进程“卡住”了,超过(比如说)一个小时还没有结束,就把它杀掉,然后继续执行(可能还会再尝试一次,循环进行)。

有什么优雅的方法可以做到这一点吗?

5 个回答

6

我之前也有类似的问题,找到了这个答案。为了完整起见,我想再补充一种方法,教你如何在一定时间后结束一个卡住的进程:可以使用Python的信号库。你可以在这里查看详细信息:https://docs.python.org/2/library/signal.html

根据文档的说明:

import signal, os

def handler(signum, frame):
    print 'Signal handler called with signal', signum
    raise IOError("Couldn't open device!")

# Set the signal handler and a 5-second alarm
signal.signal(signal.SIGALRM, handler)
signal.alarm(5)

# This open() may hang indefinitely
fd = os.open('/dev/ttyS0', os.O_RDWR)

signal.alarm(0)          # Disable the alarm

不过,由于你本来就想要启动一个新进程,这个方法可能不是解决你问题的最佳选择。

11

只要你知道进程的PID(进程标识符),使用psutil有至少两种方法可以做到这一点。

假设这个进程是这样创建的:

import subprocess
subp = subprocess.Popen(['progname'])

...你可以通过一个忙碌的循环来获取它的创建时间,像这样:

import psutil, time

TIMEOUT = 60 * 60  # 1 hour

p = psutil.Process(subp.pid)
while 1:
    if (time.time() - p.create_time()) > TIMEOUT:
        p.kill()
        raise RuntimeError('timeout')
    time.sleep(5)

...或者更简单地,你可以这样做:

import psutil

p = psutil.Process(subp.pid)
try:
    p.wait(timeout=60*60)
except psutil.TimeoutExpired:
    p.kill()
    raise

另外,顺便提一下,你可能会对以下额外的API感兴趣:

>>> p.status()
'running'
>>> p.is_running()
True
>>>
33

subprocess模块会是你的好帮手。你可以启动一个进程来获取一个Popen对象,然后把这个对象传给一个函数。需要注意的是,这个方法只会在超时时抛出异常。如果你想的话,可以捕捉这个异常,并对Popen进程调用kill()方法。(顺便说一下,kill是在Python 2.6中新增的功能)

import time

def wait_timeout(proc, seconds):
    """Wait for a process to finish, or raise exception after timeout"""
    start = time.time()
    end = start + seconds
    interval = min(seconds / 1000.0, .25)

    while True:
        result = proc.poll()
        if result is not None:
            return result
        if time.time() >= end:
            raise RuntimeError("Process timed out")
        time.sleep(interval)

撰写回答