How to make a subprocess.call timeout using python 2.7.6?

后端 未结 5 1925
暗喜
暗喜 2020-12-15 23:31

This has probably been asked but I cannot find anything regarding a subprocess.call timeout when using python 2.7

相关标签:
5条回答
  • 2020-12-15 23:55

    In python 3.3 timeout argument was added.

    https://docs.python.org/3/library/subprocess.html#subprocess.call

    0 讨论(0)
  • 2020-12-16 00:04

    You can use subprocess32 mentioned by @gps, which is backport of the subprocess standard library module from Python 3.2 - 3.5 for use on Python 2.

    Firstly, install the subprocess32 module:

    pip install subprocess32
    

    Here's a code snippet:

    >>> import subprocess32
    >>> print subprocess32.check_output(["python", "--version"])
    Python 2.7.12
    
    >>> subprocess32.check_output(["sleep", "infinity"], timeout=3)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "/usr/local/lib/python2.7/dist-packages/subprocess32.py", line 340, in check_output
        raise TimeoutExpired(process.args, timeout, output=output)
    subprocess32.TimeoutExpired: Command '['sleep', 'infinity']' timed out after 3 seconds
    

    Notice, default timeout=None, which means never timeout.

    0 讨论(0)
  • 2020-12-16 00:08

    You can try to use "easyprocess":

    https://github.com/ponty/EasyProcess

    It has many features that you need like "timeout".

    0 讨论(0)
  • 2020-12-16 00:10

    A simple way I've always done timeouts with 2.7 is utilizing subprocess.poll() alongside time.sleep() with a delay. Here's a very basic example:

    import subprocess
    import time
    
    x = #some amount of seconds
    delay = 1.0
    timeout = int(x / delay)
    
    args = #a string or array of arguments
    task = subprocess.Popen(args)
    
    #while the process is still executing and we haven't timed-out yet
    while task.poll() is None and timeout > 0:
         #do other things too if necessary e.g. print, check resources, etc.
         time.sleep(delay)
         timeout -= delay
    

    If you set x = 600, then your timeout would amount to 10 minutes. While task.poll() will query whether or not the process has terminated. time.sleep(delay) will sleep for 1 second in this case, and then decrement the timeout by 1 second. You can play around with that part to your heart's content, but the basic concept is the same throughout.

    Hope this helps!

    subprocess.poll() https://docs.python.org/2/library/subprocess.html#popen-objects

    0 讨论(0)
  • 2020-12-16 00:15

    You could install subprocess32 module mentioned by @gps -- the backport of the subprocess module from Python 3.2/3.3 for use on 2.x. It works on Python 2.7 and it includes timeout support from Python 3.3.

    subprocess.call() is just Popen().wait() and therefore to interrupt a long running process in timeout seconds:

    #!/usr/bin/env python
    import time
    from subprocess import Popen
    
    p = Popen(*call_args)
    time.sleep(timeout)
    try:
        p.kill()
    except OSError:
        pass # ignore
    p.wait()
    

    If the child process may end sooner then a portable solution is to use Timer() as suggested in @sussudio's answer:

    #!/usr/bin/env python
    from subprocess import Popen
    from threading import Timer
    
    def kill(p):
        try:
            p.kill()
        except OSError:
            pass # ignore
    
    p = Popen(*call_args)
    t = Timer(timeout, kill, [p])
    t.start()
    p.wait()
    t.cancel()
    

    On Unix, you could use SIGALRM as suggested in @Alex Martelli's answer:

    #!/usr/bin/env python
    import signal
    from subprocess import Popen
    
    class Alarm(Exception):
        pass
    
    def alarm_handler(signum, frame):
        raise Alarm
    
    signal.signal(signal.SIGALRM, alarm_handler)
    
    
    p = Popen(*call_args)
    signal.alarm(timeout)  # raise Alarm in 5 minutes
    try:
        p.wait()
        signal.alarm(0)  # reset the alarm
    except Alarm:
        p.kill()
        p.wait()
    

    To avoid using threads and signals here, subprocess module on Python 3 uses a busy loop with waitpid(WNOHANG) calls on Unix and winapi.WaitForSingleObject() on Windows.

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