Python subprocess timeout?

后端 未结 10 2112
旧时难觅i
旧时难觅i 2020-12-09 04:06

Is there any argument or options to setup a timeout for Python\'s subprocess.Popen method?

Something like this:

subprocess.Popen([\'..\'], ..., timeout

相关标签:
10条回答
  • 2020-12-09 04:27

    You could do

    from twisted.internet import reactor, protocol, error, defer
    
    class DyingProcessProtocol(protocol.ProcessProtocol):
        def __init__(self, timeout):
            self.timeout = timeout
    
        def connectionMade(self):
            @defer.inlineCallbacks
            def killIfAlive():
                try:
                    yield self.transport.signalProcess('KILL')
                except error.ProcessExitedAlready:
                    pass
    
            d = reactor.callLater(self.timeout, killIfAlive)
    
    reactor.spawnProcess(DyingProcessProtocol(20), ...)
    

    using Twisted's asynchronous process API.

    0 讨论(0)
  • 2020-12-09 04:28

    No there is no time out. I guess, what you are looking for is to kill the sub process after some time. Since you are able to signal the subprocess, you should be able to kill it too.

    generic approach to sending a signal to subprocess:

    proc = subprocess.Popen([command])
    time.sleep(1)
    print 'signaling child'
    sys.stdout.flush()
    os.kill(proc.pid, signal.SIGUSR1)
    

    You could use this mechanism to terminate after a time out period.

    0 讨论(0)
  • 2020-12-09 04:35

    Yes, https://pypi.python.org/pypi/python-subprocess2 will extend the Popen module with two additional functions,

    Popen.waitUpTo(timeout=seconds)
    

    This will wait up to acertain number of seconds for the process to complete, otherwise return None

    also,

    Popen.waitOrTerminate
    

    This will wait up to a point, and then call .terminate(), then .kill(), one orthe other or some combination of both, see docs for full details:

    http://htmlpreview.github.io/?https://github.com/kata198/python-subprocess2/blob/master/doc/subprocess2.html

    0 讨论(0)
  • 2020-12-09 04:35

    For Linux, you can use a signal. This is platform dependent so another solution is required for Windows. It may work with Mac though.

    def launch_cmd(cmd, timeout=0):
        '''Launch an external command
    
        It launchs the program redirecting the program's STDIO
        to a communication pipe, and appends those responses to
        a list.  Waits for the program to exit, then returns the
        ouput lines.
    
        Args:
            cmd: command Line of the external program to launch
            time: time to wait for the command to complete, 0 for indefinitely
        Returns:
            A list of the response lines from the program    
        '''
    
        import subprocess
        import signal
    
        class Alarm(Exception):
            pass
    
        def alarm_handler(signum, frame):
            raise Alarm
    
        lines = []
    
        if not launch_cmd.init:
            launch_cmd.init = True
            signal.signal(signal.SIGALRM, alarm_handler)
    
        p = subprocess.Popen(cmd, stdout=subprocess.PIPE)
        signal.alarm(timeout)  # timeout sec
    
        try:
            for line in p.stdout:
                lines.append(line.rstrip())
            p.wait()
            signal.alarm(0)  # disable alarm
        except:
            print "launch_cmd taking too long!"
            p.kill()
    
        return lines        
    launch_cmd.init = False
    
    0 讨论(0)
  • 2020-12-09 04:37

    I would advise taking a look at the Timer class in the threading module. I used it to implement a timeout for a Popen.

    First, create a callback:

    def timeout( p ):
        if p.poll() is None:
            print 'Error: process taking too long to complete--terminating'
            p.kill()
    

    Then open the process:

    proc = Popen( ... )
    

    Then create a timer that will call the callback, passing the process to it.

    t = threading.Timer( 10.0, timeout, [proc] )
    t.start()
    t.join()
    

    Somewhere later in the program, you may want to add the line:

    t.cancel()
    

    Otherwise, the python program will keep running until the timer has finished running.

    EDIT: I was advised that there is a race condition that the subprocess p may terminate between the p.poll() and p.kill() calls. I believe the following code can fix that:

    import errno
    
    def timeout( p ):
        if p.poll() is None:
            try:
                p.kill()
                print 'Error: process taking too long to complete--terminating'
            except OSError as e:
                if e.errno != errno.ESRCH:
                    raise
    

    Though you may want to clean the exception handling to specifically handle just the particular exception that occurs when the subprocess has already terminated normally.

    0 讨论(0)
  • 2020-12-09 04:44

    A python subprocess auto-timeout is not built in, so you're going to have to build your own.

    This works for me on Ubuntu 12.10 running python 2.7.3

    Put this in a file called test.py

    #!/usr/bin/python
    import subprocess
    import threading
    
    class RunMyCmd(threading.Thread):
        def __init__(self, cmd, timeout):
            threading.Thread.__init__(self)
            self.cmd = cmd 
            self.timeout = timeout
    
        def run(self):
            self.p = subprocess.Popen(self.cmd)
            self.p.wait()
    
        def run_the_process(self):
            self.start()
            self.join(self.timeout)
    
            if self.is_alive():
                self.p.terminate()   #if your process needs a kill -9 to make 
                                     #it go away, use self.p.kill() here instead.
    
                self.join()
    
    RunMyCmd(["sleep", "20"], 3).run_the_process()
    

    Save it, and run it:

    python test.py
    

    The sleep 20 command takes 20 seconds to complete. If it doesn't terminate in 3 seconds (it won't) then the process is terminated.

    el@apollo:~$  python test.py 
    el@apollo:~$ 
    

    There is three seconds between when the process is run, and it is terminated.

    0 讨论(0)
提交回复
热议问题