Найти - Пользователи
Полная версия: Чтение из стандартных потоков.
Начало » Python для экспертов » Чтение из стандартных потоков.
1 2 3
dxp
Задача: запустить внешнюю программу в отдельном процессе и читать порциями из ее потоков вывода - 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(), которая копит весь вывод в буфер до завершения работы запущенного процесса.

Вопрос: что я делаю неправильно? Спасибо.
poltergeist
Питон по дефолту юзает буферезированный вывод, так что он у тебя только под конец выполнения скрипта выдаст какой-нибудь результат (или при заполнении буфера).

Решение №1: запускать интерпретатор питона с ключём -u : (ex: python -u script_name.py) - т.е. включить небуферезированный вывод;
Решение №2: после каждого вывода строки (print “…”) производить принудительный вывод содержимого буфера в канал - sys.stdout.flush()
dxp
poltergeist
Питон по дефолту юзает буферезированный вывод, так что он у тебя только под конец выполнения скрипта выдаст какой-нибудь результат (или при заполнении буфера).
А почему тогда при запуске из шелла все выдается сразу? Прошу прощения, если вопрос тупой. :)

poltergeist
Решение №1: запускать интерпретатор питона с ключём -u : (ex: python -u script_name.py) - т.е. включить небуферезированный вывод;
Решение №2: после каждого вывода строки (print “…”) производить принудительный вывод содержимого буфера в канал - sys.stdout.flush()
Спасибо, оба варианта работают. Но есть одно “но”. Оба решения относятся не к самому запускающему скрипту, а к запускаемому процессу. Питон у меня тут в запуске стоит чисто для отладки. Реально там совсем другие программы будут пускаться. Получается, что поведение зависит от самой программы? Вот я написал аналогичную прогу на С++:


#include <stdio.h>
#include <windows.h>


int main()
{
for(int i = 0; i < 5; i++)
{
printf(“Slon\n”);
::Sleep(1000);
}

return 0;

}


подсовываю теперь в запуск экзешник, опять выдача идет скопом в конце. Это особенность самого этого экзешника?
dxp
Похоже, что решение лежит где-то в районе win32console.
redixin
это особенность либы stdio. когда вывод идет в tty - stdio использует линейную буферизацию, но когда вывод идет в трубу она юзает блочную. процесс может флашнуть буфер, но флашнится ли он - зависит от stdio. это все дело очень платформо-зависимо, и вообще стремно. решить можно отказом от stdio (: либо заюзать сокет
dxp
про сокет можно подробнее? Хорошо бы короткий пример.
redixin
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
bialix
как сокет поможет в вычитывании потока вывода другой программы? особенно чужой программы?
чужой - никак
своей - пример выше наглядно показывает как
dxp
redixin
bialix
как сокет поможет в вычитывании потока вывода другой программы? особенно чужой программы?
чужой - никак
своей - пример выше наглядно показывает как
Из своей все куда проще - тот же flush дает нужной поведение. Хоть из питона, хоть из С++. Задача - выдрать из буфера вывода запускаемого процесса.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB