Terminating a program within a time frame through python

懵懂的女人 提交于 2020-01-15 09:52:48

问题


I'm running a fortran code from a python script which sometimes takes a while to run. Thus I'm limiting the run time with a code taken from 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

I'm basically putting another function (partly below) in to this one (above) to run fortran code as:

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

However I realised that when fortran code takes more than 15 seconds, which is the boundary in timeout function, it leaves in the core and executes other one in the for loop which creates dump in my cores. In order to prevent that, I wanted to use subprocess.popen() since it gives me pid to terminate the job in the core, but I need to wait for the process to be executed as well, like subprocess.check_output() does. Thus I was wondaring if there is a way to combine popen and check_output properties to wait until job is done within 15 seconds and if its not just terminates that.


回答1:


Not the most sophisticated piece of code in the world but it may be useful.

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"

Edit: Problems with kill not appearing to function.
Try using os.kill(x.pid, signal.SIGKILL) rather than SIGTERM.
I believe that SIGTERM asks the process to close down cleanly, rather than terminate immediately. Not knowing what drives the fortran script, it's difficult to know what the terminate signal does. Perhaps the code is doing something.
For example:
if I ran a shell script as follows:

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

and sent it kill -15 pid_number, it would not print "signal" until the sleep had terminated after 30 seconds, whereas if I issued kill -9 pid_number it would terminate immediately with nothing printed out.

The short answer, is I don't know but I suspect that the answer lies within the script running the fortran code.

EDIT:

Note: In order to successfully run x.kill() or os.kill() or subprocess.call('kill '+ str(x.pid), shell=True), shell option in x needs to be False. Thus one can use

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

But also note that if you want to write the output to a log file by using ... >& log_file it wont work since >& is not an valid argument for your script but for your shell environment. Thus one needs to use only arguments that are valid for the script that python runs.




回答2:


There's a timeout argument on check_output, just set it to 15 seconds.

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

Documentation here https://docs.python.org/3/library/subprocess.html#subprocess.check_output

check_output returns the output as well, so if you care about it just store the result.

There's also a wait function that's useful for more complicated use cases. Both check_output and wait block until the process finishes, or until the timeout is reached.




回答3:


Additional answer to the one above, shell has an internal timeout command as well so it can be used as follows;

timeout <TIME IN SEC> ./blabla > log_file

I'm using it in python as follows;

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

Thus one can check if flag is 1 or 0 to understand what happened to the job. Note that --signal=SIGKILL is just written Killed at the end of the run if its terminated. For more signal options one can check kill -l.



来源:https://stackoverflow.com/questions/39706661/terminating-a-program-within-a-time-frame-through-python

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!