2016-07-04 1 views
1

Я пытаюсь прочитать результат подпроцесса, вызванного из Python. Для этого я использую Popen (потому что я не думаю, что можно подключить stdout при использовании subprocess.call).В чем разница между использованием universal_newlines = True (с bufsize = 1) и использованием аргументов по умолчанию с Popen

На данный момент у меня есть два способа сделать это, которые, как правило, дают те же результаты. Код выглядит следующим образом:

with Popen(['Robocopy', source, destination, '/E', '/TEE', '/R:3', '/W:5', '/log+:log.txt'], stdout=PIPE) as Robocopy: 
    for line in Robocopy.stdout: 
     line = line.decode('ascii') 
     message_list = [item.strip(' \t\n').replace('\r', '') for item in line.split('\t') if item != ''] 
     print(message_list[0], message_list[0]) 
    Robocopy.wait() 
    returncode = Robocopy.returncode 

и

with Popen(['Robocopy', source, destination, '/E', '/TEE', '/R:3', '/W:5', '/log+:log.txt'], stdout=PIPE, universal_newlines=True, bufsize=1) as Robocopy: 
    for line in Robocopy.stdout: 
     message_list = [item.strip() for item in line.split('\t') if item != ''] 
     print(message_list[0], message_list[2]) 
    Robocopy.wait() 
    returncode = Robocopy.returncode 

первый метод не включает universal_newlines = True, так как документация штатов это only usable if universal_newlines=True i.e., in a text mode.

Вторая версия включает universal_newlines, поэтому я указываю bufsize.

Может кто-нибудь объяснить мне разницу? Я не могу найти статью, но я читал о проблемах с переполняющим буфером, вызывающим какую-то проблему, и, следовательно, важность использования for line in stdout.

Кроме того, при взгляде на выходе, не уточняя universal_newlines делает стандартный вывод в bytes объекта - но я не уверен, что разница, что делает, если я просто декодировать объект байт с ascii (с точки зрения новых линий и вкладок) по сравнению universal_newlines Режим.

Наконец, установка bufsize на 1 делает вывод «строковым буфером», но я не уверен, что это значит. Я был бы признателен за объяснение того, как эти различные элементы соединяются вместе. Благодаря

ответ

4

В чем разница между использованием universal_newlines = True (с BUFSIZE = 1) и используя аргументы по умолчанию с Popen

Значения по умолчанию: universal_newlines=False (то есть вход/выход принятый как байты, а не строки Юникода плюс обработка universal newlines mode (следовательно, имя параметра, хотя text_mode, возможно, было лучшим именем здесь) отключено - вы получаете двоичные данные как есть (если только слой POSIX на Win dows messes it up) и bufsize=-1 (что означает, что потоки полностью буферизованы - используется размер буфера по умолчанию).

universal_newlines=True использует кодировку символов locale.getpreferredencoding(False) для декодирования байтов (это может отличаться от кодировки ascii, используемой в вашем коде).

Если universal_newlines=False затем for line in Robocopy.stdout: итерации свыше b'\n' -раздельные линии. Если процесс использует кодировку без ascii, например, UTF-16 для своего вывода, то даже если os.linesep == '\n' в вашей системе; вы можете получить неправильный результат. Если вы хотите использовать текстовые строки, используйте текстовый режим: перейдите universal_newlines=True или используйте io.TextIOWrapper(process.stdout) явно.

Вторая версия включает universal_newlines, поэтому я указываю bufsize.

В общем, нет необходимости указывать bufsize, если вы используете universal_newlines (вы можете, но это не обязательно). И вам не нужно указывать bufsize в вашем случае. bufsize=1 включает режим линейного буферизации (входной буфер автоматически сбрасывается по новым строкам, если вы пишете до process.stdin), в противном случае это эквивалентно по умолчанию bufsize=-1.

+0

Таким образом, значение по умолчанию 'bufsize = -1' похоже на то, что это может вызвать проблему. Полностью буферизация потока может привести к некорректной блокировке? И если он не указан (в режиме universal_newlines), разве я не создаю возможность блокировки из-за полного буфера? – Startec

+0

@Startec: no. Здесь нет проблемы блокировки (независимо от значений 'universal_newlines',' bufsize'). Откуда у вас эти идеи? Если у вас есть проблема с определенным кодом, задайте вопрос об этом конкретном коде. – jfs

+0

Мои извинения, моя путаница исходила из документации для подпроцесса (например, 'Не используйте stdout = PIPE или stderr = PIPE с этой функцией. Детский процесс будет блокироваться, если он генерирует достаточный вывод в канал для заполнения буфера для буфера OS как трубы не читаются.) ' Но теперь я вижу, что это для subprocess.call. Спасибо за ваш четкий ответ - он касается моих вопросов – Startec