Форум сайта python.su
Задача: запустить внешнюю программу в отдельном процессе и читать порциями из ее потоков вывода - stdout и stderr. Порциями - потому, что программа может выполняться длительное время и если ее вывод ожидать до ее окончания, то получается, что запустили, и сидим, ничего не видим, никакой активности, хотя на самом деле сама программа на выход постоянно выдает инфу. Некомфортно.
Запуск делаю с помощью subprocess.Popen:
p = subprocess.Popen('python.exe process.py', universal_newlines = True,
stdin = subprocess.PIPE,
stdout = subprocess.PIPE,
stderr = subprocess.PIPE)
где process.py:
for i in range(5):
print ‘Slon ’ + str(i)
time.sleep(1)
Т.е. этот тестовый процесс просто печатает пять строк с интервалом в одну секунду. Если запусить его отдельно из шелла, то все печается, как положено.
Далее, вычитывание делаю так:
Done = False
while Done != True:
s = p.stdout.readline()
sys.stdout.write(s)
if s == '':
Done = True
Т.е. пытаюсь читать по одной строке до поступления пустой строки, которая должна означать EOF (про poll() знаю, но в данном случае это не суть важно). Так вот, проблема в том, что построчного вычитывания и вывода не происходит - программа зависает на пять секунд и потом выдает все 5 строк сразу. Т.е. поведение как в случае с функций communicate(), которая копит весь вывод в буфер до завершения работы запущенного процесса.
Вопрос: что я делаю неправильно? Спасибо.
Отредактировано (Ноя. 23, 2007 12:22:03)
Офлайн
Питон по дефолту юзает буферезированный вывод, так что он у тебя только под конец выполнения скрипта выдаст какой-нибудь результат (или при заполнении буфера).
Решение №1: запускать интерпретатор питона с ключём -u : (ex: python -u script_name.py) - т.е. включить небуферезированный вывод;
Решение №2: после каждого вывода строки (print “…”) производить принудительный вывод содержимого буфера в канал - sys.stdout.flush()
Офлайн
poltergeistА почему тогда при запуске из шелла все выдается сразу? Прошу прощения, если вопрос тупой. :)
Питон по дефолту юзает буферезированный вывод, так что он у тебя только под конец выполнения скрипта выдаст какой-нибудь результат (или при заполнении буфера).
poltergeistСпасибо, оба варианта работают. Но есть одно “но”. Оба решения относятся не к самому запускающему скрипту, а к запускаемому процессу. Питон у меня тут в запуске стоит чисто для отладки. Реально там совсем другие программы будут пускаться. Получается, что поведение зависит от самой программы? Вот я написал аналогичную прогу на С++:
Решение №1: запускать интерпретатор питона с ключём -u : (ex: python -u script_name.py) - т.е. включить небуферезированный вывод;
Решение №2: после каждого вывода строки (print “…”) производить принудительный вывод содержимого буфера в канал - sys.stdout.flush()
Офлайн
Похоже, что решение лежит где-то в районе win32console.
Офлайн
это особенность либы stdio. когда вывод идет в tty - stdio использует линейную буферизацию, но когда вывод идет в трубу она юзает блочную. процесс может флашнуть буфер, но флашнится ли он - зависит от stdio. это все дело очень платформо-зависимо, и вообще стремно. решить можно отказом от stdio (: либо заюзать сокет
Офлайн
про сокет можно подробнее? Хорошо бы короткий пример.
Офлайн
http://mail.python.org/pipermail/python-list/2007-October/463815.html
(первая строчка в гугле по запросу python socket AF_UNIX example)
# Echo server program
import socket,os
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
try:
os.remove("/tmp/socketname")
except OSError:
pass
s.bind("/tmp/socketname")
s.listen(1)
conn, addr = s.accept()
while 1:
data = conn.recv(1024)
if not data: break
conn.send(data)
conn.close()
# Echo client program
import socket
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
s.connect("/tmp/socketname")
s.send('Hello, world')
data = s.recv(1024)
s.close()
print 'Received', repr(data)
Офлайн
как сокет поможет в вычитывании потока вывода другой программы? особенно чужой программы?
Офлайн
bialixчужой - никак
как сокет поможет в вычитывании потока вывода другой программы? особенно чужой программы?
Офлайн
redixinИз своей все куда проще - тот же flush дает нужной поведение. Хоть из питона, хоть из С++. Задача - выдрать из буфера вывода запускаемого процесса.bialixчужой - никак
как сокет поможет в вычитывании потока вывода другой программы? особенно чужой программы?
своей - пример выше наглядно показывает как
Офлайн