Лучшее многопоточное использование подпроцесса Python. Открыть и общаться ()? - PullRequest
3 голосов
/ 26 ноября 2010

Я выполняю несколько команд, которые могут занять некоторое время параллельно на машине Linux с Python 2.6.

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

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() параллельно?

Ответы [ 3 ]

2 голосов
/ 28 ноября 2010

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

http://bitbucket.org/daybreaker/kaist-cs443/src/247f9ecf3cee/tools/manage.py

Кажется, это ошибка Python.

0 голосов
/ 14 мая 2011

В вашем примере кода я заметил, что вы используете:

for line in output.splitlines(): 

для частичного решения вопроса " / r "; использование

for line in output.splitlines(True): 

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

0 голосов
/ 26 ноября 2010

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

...