Уведомления

Группа в Telegram: @pythonsu

#1 Ноя. 23, 2007 12:10:18

dxp
От:
Зарегистрирован: 2007-11-23
Сообщения: 6
Репутация: +  0  -
Профиль   Отправить e-mail  

Чтение из стандартных потоков.

Задача: запустить внешнюю программу в отдельном процессе и читать порциями из ее потоков вывода - 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)

Офлайн

#2 Ноя. 23, 2007 14:49:35

poltergeist
От:
Зарегистрирован: 2007-02-28
Сообщения: 522
Репутация: +  0  -
Профиль   Отправить e-mail  

Чтение из стандартных потоков.

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

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



Офлайн

#3 Ноя. 23, 2007 16:01:31

dxp
От:
Зарегистрирован: 2007-11-23
Сообщения: 6
Репутация: +  0  -
Профиль   Отправить e-mail  

Чтение из стандартных потоков.

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;

}


подсовываю теперь в запуск экзешник, опять выдача идет скопом в конце. Это особенность самого этого экзешника?



Офлайн

#4 Ноя. 24, 2007 12:51:02

dxp
От:
Зарегистрирован: 2007-11-23
Сообщения: 6
Репутация: +  0  -
Профиль   Отправить e-mail  

Чтение из стандартных потоков.

Похоже, что решение лежит где-то в районе win32console.



Офлайн

#5 Ноя. 24, 2007 14:14:53

redixin
От:
Зарегистрирован: 2006-11-27
Сообщения: 66
Репутация: +  1  -
Профиль   Отправить e-mail  

Чтение из стандартных потоков.

это особенность либы stdio. когда вывод идет в tty - stdio использует линейную буферизацию, но когда вывод идет в трубу она юзает блочную. процесс может флашнуть буфер, но флашнится ли он - зависит от stdio. это все дело очень платформо-зависимо, и вообще стремно. решить можно отказом от stdio (: либо заюзать сокет



Офлайн

#6 Ноя. 24, 2007 14:44:19

dxp
От:
Зарегистрирован: 2007-11-23
Сообщения: 6
Репутация: +  0  -
Профиль   Отправить e-mail  

Чтение из стандартных потоков.

про сокет можно подробнее? Хорошо бы короткий пример.



Офлайн

#7 Ноя. 24, 2007 16:50:52

redixin
От:
Зарегистрирован: 2006-11-27
Сообщения: 66
Репутация: +  1  -
Профиль   Отправить e-mail  

Чтение из стандартных потоков.

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)



Офлайн

#8 Ноя. 24, 2007 17:22:28

bialix
От:
Зарегистрирован: 2006-07-13
Сообщения: 774
Репутация: +  1  -
Профиль   Отправить e-mail  

Чтение из стандартных потоков.

как сокет поможет в вычитывании потока вывода другой программы? особенно чужой программы?



Офлайн

#9 Ноя. 24, 2007 21:36:05

redixin
От:
Зарегистрирован: 2006-11-27
Сообщения: 66
Репутация: +  1  -
Профиль   Отправить e-mail  

Чтение из стандартных потоков.

bialix
как сокет поможет в вычитывании потока вывода другой программы? особенно чужой программы?
чужой - никак
своей - пример выше наглядно показывает как



Офлайн

#10 Ноя. 25, 2007 09:41:48

dxp
От:
Зарегистрирован: 2007-11-23
Сообщения: 6
Репутация: +  0  -
Профиль   Отправить e-mail  

Чтение из стандартных потоков.

redixin
bialix
как сокет поможет в вычитывании потока вывода другой программы? особенно чужой программы?
чужой - никак
своей - пример выше наглядно показывает как
Из своей все куда проще - тот же flush дает нужной поведение. Хоть из питона, хоть из С++. Задача - выдрать из буфера вывода запускаемого процесса.



Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version