2009-02-09 9 views
21

Если это мой подпроцесс:Перехватив стандартный вывод подпроцесс в то время как он работает

import time, sys 
for i in range(200): 
    sys.stdout.write('reading %i\n'%i) 
    time.sleep(.02) 

И это сценарий управления и изменения выходного подпроцесса:

import subprocess, time, sys 

print 'starting' 

proc = subprocess.Popen(
    'c:/test_apps/testcr.py', 
    shell=True, 
    stdin=subprocess.PIPE, 
    stdout=subprocess.PIPE ) 

print 'process created' 

while True: 
    #next_line = proc.communicate()[0] 
    next_line = proc.stdout.readline() 
    if next_line == '' and proc.poll() != None: 
     break 
    sys.stdout.write(next_line) 
    sys.stdout.flush() 

print 'done' 

Почему readline и communicate Ожидание до завершения процесса? Есть ли простой способ передать (и изменить) подпроцесс 'stdout в режиме реального времени?

BTW, я видел this, но мне не нужны функции ведения журнала (и я не знаю, что это такое).

Я нахожусь в Windows XP.

+0

Связанный: [? Как очистить выход Python печати] (http://stackoverflow.com/q/230751/95735) –

ответ

14

Как уже упоминал Чарльз, проблема буферизации. Я столкнулся с аналогичной проблемой при написании некоторых модулей для SNMPd и решил ее, заменив stdout на версию с автоматической очисткой.

Я использовал следующий код, вдохновленный некоторые должности на ActiveState:

class FlushFile(object): 
    """Write-only flushing wrapper for file-type objects.""" 
    def __init__(self, f): 
     self.f = f 
    def write(self, x): 
     self.f.write(x) 
     self.f.flush() 

# Replace stdout with an automatically flushing version 
sys.stdout = FlushFile(sys.__stdout__) 
+0

Я не вижу, как это происходит иначе, чем вызов sys.stdout.flush() после каждого sys.stdout.readline(), что я и делаю. Я также попытался установить bufsize = 0 для подпроцесса. – Paul

+9

Флеш необходим в подпроцессе, а не в родительском процессе. – bobince

+0

Да, в примере подпроцесс также является скриптом python. Поэтому замените stdout в подпроцессе. Вызов sys.stdout.flush() в родительском процессе ничего не делает. –

7

Выход процесса буферизирован. В более операционных системах UNIXy (или Cygwin) доступен модуль pexpect, в котором перечислены все необходимые заклинания, чтобы избежать проблем, связанных с буферизацией. Тем не менее, эти заклинания требуют рабочего pty module, который не доступен для встроенных (не-cygwin) win32-сборников Python.

В примере, в котором вы управляете подпроцессом, вы можете просто позвонить ему sys.stdout.flush(), если необходимо, но для произвольных подпроцессов эта опция недоступна.

См. Также the question "Why not just use a pipe (popen())?" в разделе вопросов о pexpect.