2013-03-17 3 views
0

Я запускаю программу из скрипта python (в настоящее время с os.system). Однако иногда программа зависает в какой-то момент, и я бы хотел ее убить, если ничего не было записано в stdout или stderr через определенный промежуток времени. Простой тайм-аут в программе не будет работать, потому что этот код обычно работает очень долго (от нескольких часов до нескольких дней), а иногда он зависает, прежде чем ему еще предстоит пройти долгий путь.Как убить подпроцесс, если никакой активности в stdout/stderr

Кажется, что subprocess.Popen - это путь, но я не нашел хороший пример того, как это сделать. Я также хотел написать stdout/stderr в файл.

Основываясь на некоторых примерах, я думал о чем-то вроде этого:

p = Popen(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None) 

while True: 
    line = p.stdout.readline() 
    outfile.write(line) 
    # save current time or something, compare to time of 
    # previous loop, if larger than timeout, kill process 

Но я не уверен, как реализовать петлю времени, и как убедиться в том, что while не работает вечно, когда процесс в конечном итоге заканчивается сам по себе (и не вешает). Любые указатели будут высоко оценены.

+0

Почему бы не исправить ошибку в дочернем процессе, так что не висит? –

+0

@JohnZwinck, да, это, конечно, лучшее решение. Однако в этом случае это редкое явление и очень сложно воспроизвести. В некоторых случаях он также зависает по причинам вне процесса (например, файловая система и т. Д.). – tiago

ответ

1

Попробуйте использовать signal.alarm, чтобы установить таймер после приема каждой строки, а затем обработать SIGALRM, проверив, прошло ли слишком много времени со времени последней строки.

+0

Спасибо. 'signal.alarm' действительно классный. Мне удалось реализовать то, что я хотел использовать. – tiago

1

Для полноты, вот код, который я закончил с использованием, воспользовавшись предложенной signal.alarm:

import time 
import shlex 
import subprocess 

logfile = open(log, 'w', 1) 
# cmd is command to run 
args = shlex.split(cmd) # tokenise args list 
p = subprocess.Popen(args, shell=False, bufsize=0, stdin=None, 
        stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 

def _handler(signum, frame): 
    print('Timeout of %s min reached, stopping execution' % timeout) 
    p.kill() 
    time.sleep(30) # to ensure no ghost process is left running 
    raise RuntimeError('Timeout') 

signal.signal(signal.SIGALRM, _handler) 
try: 
    while True: 
     signal.alarm(int(timeout)) 
     inline = p.stdout.readline() 
     if not inline: 
      break 
     logfile.write(inline) 
     signal.alarm(0) 
except RuntimeError: 
    logfile.close() 
    return 0 

p.communicate() # wait for process to finish, get return code 
logfile.close() 
return p.returncode 
+0

Вы уверены, что ваш код работает? Я пробовал, но подпроцесс убивается немедленно. –

+0

@PedroLobito Да, я регулярно управлял этим годами. Возможно, он не очень портативен и не работает во всех системах? Я запустил его на Linux и Python 2.7. – tiago

+0

Спасибо @tiago, я попробую еще раз. –

Смежные вопросы