Я запускаю несколько команд, которые могут проходить некоторое время параллельно на 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()
в параллель?
`.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
Вот сценарий, который запускает все процессы в параллельном и групповом выводах группой процессов, сохраняя заказ в группе. https://gist.github.com/717467 – jfs 2010-11-27 01:50:45
Спасибо за Себастьяна, но ваше решение не решило проблему полностью. Кажется, это ошибка в реализации подпроцесса Python и ее синхронизации. В качестве ответа я добавил окончательный результат. – Achimnol 2010-11-28 20:15:43