Как сделать тайм-аут subprocess.call с помощью python 2.7.6?

Это, вероятно, было задано, но я не могу найти ничего относительно тайм-аута subprocess.call при использовании python 2.7

Ответы

Ответ 1

Простой способ, которым я всегда делал тайм-ауты с 2.7, - это использовать subprocess.poll() вместе с time.sleep() с задержкой. Вот очень простой пример:

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

Если вы установите x = 600, то ваше время ожидания составит 10 минут. В то время как task.poll() будет запрашивать, завершен ли процесс. time.sleep(delay) будет спать в течение 1 секунды, а затем уменьшит время ожидания на 1 секунду. Вы можете поиграть с этой частью вашего сердца, но основная концепция остается неизменной.

Надеюсь это поможет!

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

Ответ 2

Вы можете установить subprocess32 модуль упомянутый @gps - backport модуля subprocess от Python 3.2/3.3 для использования на 2.x. Он работает на Python 2.7 и включает поддержку тайм-аута от Python 3.3.

subprocess.call() - это просто Popen().wait() и поэтому прерывать длительный процесс в timeout секунды:

#!/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()

Если дочерний процесс может закончиться раньше, то портативное решение будет использовать Timer(), как указано в ответе @sussudio:

#!/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()

В Unix вы можете использовать SIGALRM, как указано в ответе @Alex Martelli:

#!/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()

Чтобы избежать использования потоков и сигналов здесь, модуль subprocess на Python 3 использует цикл занятости с вызовами waitpid(WNOHANG) в Unix и winapi.WaitForSingleObject() в Windows.

Ответ 3

Вы можете попробовать использовать "easyprocess" :

https://github.com/ponty/EasyProcess

В нем есть много функций, которые вам нужны, например, "Тайм-аут" .

Ответ 4

Вы можете использовать подпроцесс32, упомянутый @gps, который является обратным портом модуля стандартной библиотеки подпроцесса из Python 3.2 - 3.5 для использования в Python 2.

Во-первых, установите модуль subprocess32:

pip install subprocess32

Вот фрагмент кода:

>>> 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

Обратите внимание, время timeout=None умолчанию timeout=None, что означает, что время ожидания никогда не будет.