Сбой тайм-аута подпроцесса

Я хочу использовать таймаут на подпроцессе

 from subprocess32 import check_output
 output = check_output("sleep 30", shell=True, timeout=1)

К сожалению, пока это вызывает ошибку тайм-аута, она делает это через 30 секунд. Кажется, что check_output не может прервать команду оболочки.

Что я могу сделать на стороне Python, чтобы остановить это? Я подозреваю, что subprocess32 не может убить процесс с выдержкой времени.

Ответы

Ответ 1

check_output() с тайм-аутом в основном:

with Popen(*popenargs, stdout=PIPE, **kwargs) as process:
    try:
        output, unused_err = process.communicate(inputdata, timeout=timeout)
    except TimeoutExpired:
        process.kill()
        output, unused_err = process.communicate()
        raise TimeoutExpired(process.args, timeout, output=output)

Есть две проблемы:

Это приводит к поведению, которое вы наблюдали: TimeoutExpired происходит через секунду, оболочка убита, но check_output() возвращается только через 30 секунд после завершения процесса grandchild sleep.

Чтобы обойти проблемы, уничтожьте все дерево процессов (все подпроцессы, принадлежащие к одной группе):

#!/usr/bin/env python3
import os
import signal
from subprocess import Popen, PIPE, TimeoutExpired
from time import monotonic as timer

start = timer()
with Popen('sleep 30', shell=True, stdout=PIPE, preexec_fn=os.setsid) as process:
    try:
        output = process.communicate(timeout=1)[0]
    except TimeoutExpired:
        os.killpg(process.pid, signal.SIGINT) # send signal to the process group
        output = process.communicate()[0]
print('Elapsed seconds: {:.2f}'.format(timer() - start))

Выход

Elapsed seconds: 1.00