2017-02-09 4 views
0

Если я использую subprocess.Popen, я могу использовать communicate() для небольших выходов.Альтернатива subprocess.Popen.communicate() для потоковой передачи

Но если подпроцесс займет значительное время и даст значительный результат, я хочу получить к нему доступ в виде потоковых данных.

Есть ли способ сделать это? Документы Python сказать

Предупреждение: Используйте communicate() вместо .stdin.write, .stdout.read или .stderr.read избежать тупиков в связи с каким-либо из других буферов OS труб, заполняющих и блокирования дочернего процесса.

Я бы очень хотел, чтобы получить доступ к выходному процессу в качестве файлового типа объекта:

with someMagicFunction(['path/to/some/command','arg1','arg2','arg3']) as outpipe: 
    # pass outpipe into some other function that takes a file-like object 

, но не могу понять, как это сделать.

ответ

1

communicate - метод удобства, который начинает использовать фоновые потоки для чтения stdout и stderr. Вы можете просто прочитать stdout, но вам нужно выяснить, что делать с stderr. Если вас не волнуют ошибки, вы можете добавить параметр stderr=open(os.devnull, 'wb') или в файл stderr=open('somefile', 'wb'). Или создайте свой собственный фоновый поток для чтения. Оказывается, что shutil уже имеет такую ​​функцию, поэтому мы можем ее использовать.

import subprocess 
import threading 
import shutil 
import io 

err_buf = io.BytesIO() 

proc = subprocess.Popen(['ls', '-l'], 
    stdout=subprocess.PIPE, stderr=subprocess.PIPE) 
err_thread = threading.Thread(target=shutil.copyfileobj, 
    args=(proc.stderr, err_buf)) 
err_thread.start() 
for line in proc.stdout: 
    print(line.decode('utf-8'), end='') 
retval = proc.wait() 
err_thread.join() 
print('error:', err_buf.getvalue()) 
+0

О, это умно - спасибо! –

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