通过 python 在时间范围内终止程序

Terminating a program within a time frame through python

我正在 运行 从 python 脚本中获取 Fortran 代码,有时需要一段时间才能 运行。因此,我使用取自 this link:

的代码来限制 运行 时间
def timeout(func, args=(), kwargs={}, timeout_duration=15, default=1):
    import signal

    class TimeoutError(Exception):
        pass

    def handler(signum, frame):
        raise TimeoutError()

    # set the timeout handler
    signal.signal(signal.SIGALRM, handler) 
    signal.alarm(timeout_duration)
    try:
        result = func(*args, **kwargs)
    except TimeoutError as exc:
        result = default
    finally:
        signal.alarm(0)

    return result

我基本上是将另一个函数(部分在下方)放入这个(上方)到 运行 fortran 代码中:

subprocess.check_output('./../bin/SPhenoUMSSM ../UMSSM/LH_out_'+mod+' > SPheno_log_'+mod, shell=True)

但是我意识到当 fortran 代码花费超过 15 秒时,这是超时函数的边界,它会留在核心中并在 for 循环中执行另一个代码,这会在我的核心中创建转储。为了防止这种情况,我想使用 subprocess.popen() 因为它给我 pid 来终止核心中的作业,但我也需要等待进程执行,就像 subprocess.check_output() 一样。因此,我想知道是否有一种方法可以组合 popen 和 check_output 属性以等待作业在 15 秒内完成,如果它不只是终止它。

check_output 上有一个超时参数,只需将其设置为 15 秒即可。

try:
  subprocess.check_output(['arg1', 'arg2'], timeout=15)
except:
  print("Timed out")

这里有文档https://docs.python.org/3/library/subprocess.html#subprocess.check_output

check_output returns 输出也是如此,所以如果您关心它,只需存储结果即可。

还有一个等待函数,可用于更复杂的用例。 check_output 和 wait 都会阻塞,直到进程完成或达到超时。

这不是世界上最复杂的代码,但它可能很有用。

import subprocess, time
x = subprocess.Popen(['sleep', '15'])
polling = None
i = 0
while polling == None:
    time.sleep(1)
    polling = x.poll()
    i +=1
    if i > 15: break
if polling == None:
    try:
        x.kill()
        print "Time out - process terminated" # process terminated by kill command
    except OSError:
        print "Process completed on time" # process terminated between poll and kill commands
    except Exception as e:
        print "Error "+str(e) # kill command failed due to another exception "e"
else:
    print "Process Completed after "+str(i)+" seconds"

编辑:kill 似乎没有起作用的问题。
尝试使用 os.kill(x.pid, signal.SIGKILL) 而不是 SIGTERM.
我相信 SIGTERM 要求进程彻底关闭,而不是立即终止。不知道是什么驱动了 fort运行 脚本,就很难知道终止信号的作用。也许代码正在做一些事情。
例如:
如果我 运行 一个 shell 脚本如下:

#!/bin/bash
trap "echo signal" 15
sleep 30

并发送它 kill -15 pid_number,它不会打印 "signal" 直到睡眠在 30 秒后终止,而如果我发出 kill -9 pid_number 它会立即终止而不会打印任何内容。

简短的回答是,我不知道,但我怀疑答案就在 运行 堡垒 运行 代码的脚本中。

编辑:

注意:为了成功 运行 x.kill()os.kill()subprocess.call('kill '+ str(x.pid), shell=True),x 中的 shell 选项需要为 False。因此可以使用

import shlex
args = shlex.split(ARGS HERE) 
x = subprocess.Popen(args) # shell=False is default

但还要注意,如果你想使用 ... >& log_file 将输出写入日志文件,它不会工作,因为 >& 不是你的脚本的有效参数,而是你的 shell 环境。因此,只需要使用对 python 运行s.

脚本有效的参数

对上述问题的补充回答,shell 也有一个内部超时命令,因此可以按如下方式使用;

timeout <TIME IN SEC> ./blabla > log_file

我在 python 中使用它如下;

try:
    check_output('timeout --signal=SIGKILL 12 ./<COMMAND> > log', shell=True)
    flag = 0
except:
    flag = 1

因此可以检查标志是 1 还是 0 以了解作业发生了什么。请注意,如果 --signal=SIGKILL 终止,则它只是在 运行 的末尾写入 Killed。有关更多信号选项,可以查看 kill -l.