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

时间:2016-09-26 15:24:02

标签: python subprocess popen

我正在运行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秒内完成作业,并且它不仅仅是终止它,那么我很感兴趣。

3 个答案:

答案 0 :(得分:1)

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

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"

编辑:杀人问题似乎无法正常运作 尝试使用os.kill(x.pid, signal.SIGKILL)而不是SIGTERM 我相信SIGTERM要求流程干净地关闭,而不是立即终止。不知道是什么驱动了fortran脚本,很难知道终止信号的作用。也许代码正在做点什么 例如:
如果我按如下方式运行shell脚本:

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

并发送它kill -15 pid_number,它将不会打印“信号”,直到睡眠在30秒后终止,而如果我发出kill -9 pid_number它将立即终止而没有打印出来。

简短的回答是,我不知道,但我怀疑答案在于运行fortran代码的脚本。

编辑:

注意:为了成功运行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运行的脚本有效的参数。

答案 1 :(得分:0)

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也会返回输出,所以如果你关心它,只需存储结果。

还有一个等待功能对于更复杂的用例非常有用。 check_output和wait阻止,直到进程结束,或者直到达到超时。

答案 2 :(得分:0)

上面的一个补充答案,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。如需更多信号选项,可以查看 axios.defaults.baseURL='http://localhost:4000/';