Home > OS >  Stop an executable called via Python after specified amount of time
Stop an executable called via Python after specified amount of time

Time:10-18

I am working with a groundwater modeling executable (HYDRUS1D) which I call with a Python script. I want to do some Monte Carlo runs but sometimes the program gets hung up and does not converge for extended periods of time. Is there a way to give the executable a certain amount of time to run, cancel it if it goes over this time, and then start a new simulation all without interrupting the Python script? The simulation should take no more than 3-5 seconds, so I am hoping to give it a maximum of 10 seconds to finish.

I first run a function that changes some input parameters to the model, then execute Hydrus via the 'run_single_sim' function:

for value in n_variations_21:
    for value2 in n_variations_23:
        write_hydraulic_params('foo',layers,value,value2)
        run_single_sim()

Where run_single_sim() executes Hydrus via os.system:

def run_single_sim():
    os.system('./hydrus LEVEL_01.DIR')

I have tried a few solutions involving threading such as this, and this; but it seems like my script gets stuck on the os.system call and therefore cannot check to see how long the thread has been running or kill the thread after sleeping the script for some specified amount of time.

CodePudding user response:

You asked "how to stop an executable called via Python ...", but I feel this question is simply about "how to stop an executable". What's interesting is that we have a child that might misbehave. The parent is uninteresting, could be rust, ruby, random other language.

The timeout issue you pose is a sensible question, and there's a stock answer for it, in the GNU coreutils package.

Instead of

    os.system('./hydrus LEVEL_01.DIR')

you want

    os.system('timeout 10 ./hydrus LEVEL_01.DIR')

Here is a quick demo, using a simpler command than hydrus.

$ timeout 2  sleep 1; echo $?
0
$
$ timeout 2  sleep 3; echo $?
124

As an entirely separate matter, prefer check_output() over the old os.system().


You quoted a pair of answer articles that deal with threading. But you're spawning a separate child process, with no shared memory, so threading's not relevant here. We wish to eventually send a SIGTERM signal to an ill behaved process, and we hope it obeys the signal by quickly dropping out. Timing out a child that explicitly ignores such signals would be a slightly stickier problem. An uncatchable SIGKILL can be sent by using the --kill-after=duration flag.

  • Related