4

I want to execute an external program in each thread of a multi-threaded python program.

Let's say max running time is set to 1 second. If started process completes within 1 second, main program capture its output for further processing. If it doesn't finishes in 1 second, main program just terminate it and start another new process.

How to implement this?

M. Tibbits
  • 8,400
  • 8
  • 44
  • 59
jack
  • 17,261
  • 37
  • 100
  • 125
  • related: [subprocess with timeout](http://stackoverflow.com/q/1191374/4279) – jfs Jan 06 '15 at 06:59
  • related: [Stop reading process output in Python without hang?](http://stackoverflow.com/a/4418891/4279) – jfs Jan 06 '15 at 06:59

4 Answers4

6

You could poll it periodically:

import subprocess, time

s = subprocess.Popen(['foo', 'args'])
timeout = 1
poll_period = 0.1
s.poll()
while s.returncode is None and timeout > 0:
    time.sleep(poll_period)
    timeout -= poll_period
    s.poll()
if timeout <= 0:
    s.kill() # timed out
else:
    pass # completed

You can then just put the above in a function and start it as a thread.

Liquid_Fire
  • 6,990
  • 2
  • 25
  • 22
3

This is the helper function I use:

def run_with_timeout(command, timeout):
    import time
    import subprocess

    p = subprocess.Popen(command, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

    while timeout > 0:
        if p.poll() is not None:
            return p.communicate()
        time.sleep(0.1)
        timeout -= 0.1
    else:
        try:
            p.kill()
        except OSError as e:
            if e.errno != 3:
                raise
    return (None, None)
Cenk Alti
  • 2,792
  • 2
  • 26
  • 25
  • 1. It doesn't return any output if `command` generates big output (enough to fill its OS stdout/stderr pipe buffer). You should read the output while waiting for the timeout. 2. (minor detail) If `timeout` is large then the loop drifts because `time.sleep(0.1)` can sleep less/more than `0.1` seconds. You could use `while endtime > timer():` instead. – jfs Jan 06 '15 at 07:05
1

here is a solution using the pexpect module (I needed to capture the output of the program before it ran into the timeout, I did not manage to do this with subprocess.Popen):

import pexpect

timeout = ... # timeout in seconds

proc = pexpect.spawn('foo', ['args'], timeout = timeout)

result = proc.expect([ pexpect.EOF, pexpect.TIMEOUT])

if result == 0:
  # program terminated by itself
  ...
else:
  # result is 1 here, we ran into the timeout
  ...

print "program's output:", print proc.before
Andre Holzner
  • 18,333
  • 6
  • 54
  • 63
1

A nasty hack on linux is to use the timeout program to run the command. You may opt for a nicer all Python solution, however.

fmark
  • 57,259
  • 27
  • 100
  • 107