2010-11-26 2 views
3

Я запускаю несколько команд, которые могут проходить некоторое время параллельно на Linux-машине под управлением Python 2.6.Лучшее многопотоковое использование подпроцесса Python.Popen & communication()?

Итак, я использовал subprocess.Popen класс и process.communicate() метод для параллельного выполнения командных групп mulitple и захвата вывода сразу после выполнения.

def run_commands(commands, print_lock): 
    # this part runs in parallel. 
    outputs = [] 
    for command in commands: 
     proc = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE, stderr=subprocess.STDOUT, close_fds=True) 
     output, unused_err = proc.communicate() # buffers the output 
     retcode = proc.poll()     # ensures subprocess termination 
     outputs.append(output) 
    with print_lock: # print them at once (synchronized) 
     for output in outputs: 
      for line in output.splitlines(): 
       print(line) 

В где-то это называется так:

processes = [] 
print_lock = Lock() 
for ...: 
    commands = ... # a group of commands is generated, which takes some time. 
    processes.append(Thread(target=run_commands, args=(commands, print_lock))) 
    processes[-1].start() 
for p in processes: p.join() 
print('done.') 

Ожидаемый результат в том, что каждый выход из группы команд сразу отображается во время их исполнения осуществляется параллельно.

Но из второй группы результатов (конечно, поток, который становится вторым, изменяется из-за неопределенности планирования), он начинает печатать без строк новой строки и добавляет пробелы столько, сколько количества символов, напечатанных в каждой предыдущей строке, входное эхо выключено - состояние терминала «искажено» или «разбито». (Если я выдаю команду ракеты reset, она восстанавливается нормально.)

Сначала я попытался найти причину из обращения '\r', но это не было причиной. Как вы видите в моем коде, я обработал его правильно, используя splitlines(), и я подтвердил, что с функцией repr(), примененной к выходу.

Я думаю, что причиной является одновременное использование труб в Popen и communicate() для stdout/stderr. Я попробовал check_output метод быстрого доступа в Python 2.7, но не успел. Конечно, проблема, описанная выше, не возникает, если я сериализую все исполнения команд и отпечатки.

Есть ли лучший способ обработки Popen и communicate() в параллель?

+1

`.communicate()` обеспечивает завершение процесса из-за его вызова `Popen.wait()`. Но `proc.poll()` не обеспечивает завершение процесса. Он возвращает `None`, если процесс не завершен. Например, в Linux он вызывает `waitpid (pid, WNOHANG)`. Документы для `WNOHANG` говорят:« Функция waitpid() не приостанавливает выполнение вызывающего потока, если статус не доступен сразу для одного из дочерних процессов, заданного pid ». http://www.mkssoftware.com/docs/man3/waitpid.3.asp – jfs 2010-11-26 19:57:08

+1

Вот сценарий, который запускает все процессы в параллельном и групповом выводах группой процессов, сохраняя заказ в группе. https://gist.github.com/717467 – jfs 2010-11-27 01:50:45

+0

Спасибо за Себастьяна, но ваше решение не решило проблему полностью. Кажется, это ошибка в реализации подпроцесса Python и ее синхронизации. В качестве ответа я добавил окончательный результат. – Achimnol 2010-11-28 20:15:43

ответ

0

Я не уверен, что понятно, что нужно делать с run_commands, но, похоже, просто делает опрос на подпроцессе, игнорируя обратный код и продолжая цикл. Когда вы дойдете до той части, где вы печатаете вывод, как вы узнали, что подпроцессы завершены?

0

В вашем примере кода я заметил ваше использование:

for line in output.splitlines(): 

для решения частично вопрос «»; использование

for line in output.splitlines(True): 

было бы полезно.

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