Найти - Пользователи
Полная версия: bufsize в subprocess.Popen - баг или фича ? Давайте разберемся.
Начало » Python для экспертов » bufsize в subprocess.Popen - баг или фича ? Давайте разберемся.
1 2
JOHN_16
Итак, задача: вызвать интерпретатор, передать ему имя файла для исполнения, по ходу его выполнения перехватывать вывод. Т.о. есть программа one.py которая вызывает two.py, которая выводит на стан.поток вывода строки, которые программа one.py должна перехватить и вывести на экран. Суть проблемы заключается в том что если two.py выведет небольшое значение , например сделает print "hello world' то оно не выведется программой one.py, так как будет ждать пока заполнится буфер или two.py сделает sys.stdout.flush(). Как раз для этого случая есть параметр bufsize, описание которого гласит:

bufsize если задан, имеет тоже значение, что и передаваемый параметр в встроенную функцию open(): 0 – без буферизации, 1 – линейная буферизация, любое другое положительное значение – использование буфера заданным размером (значение будет аппроксимировано), любое другое отрицательное значение - использование системных настроек по умолчанию, что обычно означает полную буферизацию.
Но игра с параметрами не дала ожидаемого эффекта, точнее поведение вообще не менялось. Для тестирования были написаны программы one.py и two.py, последняя раз в секунду делает print строки длиною 1024 символа. Запустив one.py увидел как на экран “пачками” появляется вывод two.py причем для python 2.7 эти пачки были по 4 итерации т.е. по 4кб, для python 3.1.3 по 8кб. На Windows проблема таже.

Постарался максимально полно изложить проблему. Есть ли здесь пути решения? Это баг питона или “фича”? Может я чего то не понимаю? Буду рад конструктивным мыслям.

one.py
# -*- coding: utf-8 -*-
import subprocess, sys

# python для вызова версии 2.7, python3 для вызова 3.1.3
p=subprocess.Popen(['python','./two.py'], stdout=subprocess.PIPE, bufsize=0)
sys.stdout.write('start\n')

s=True
while s:
s=p.stdout.readline()
sys.stdout.write(str(s.rstrip())+'\n')

sys.stdout.write('end\n')
two.py
# -*- coding: utf-8 -*-
from time import sleep
import sys

i=0
while True:
# строка длиной 1024
s='iteration #%000i'%i
s=s+'*'*(1023-len(s))+'\n'
sys.stdout.write(s)
i+=1
sleep(1)
Ed
Это Питон буферизирует. Попробуйте .
Андрей Светлов
В two.py делайте sys.stdout.flush() после каждого sys.stdout.write(s).
one.py менять не нужно.
Ed
Андрей Светлов
В two.py делайте sys.stdout.flush() после каждого sys.stdout.write(s).
one.py менять не нужно.
Это он знает. В первом посте упоминалось.
o7412369815963
я flush() добавил - заработало.
o7412369815963
возможно так!?:
bufsize регулирует буферизацию one.py (при приеме), но у two.py есть свой буфер (при отдаче).
Ed
Вы меня видимо не поняли. Попробую пояснить на примере.
Если вместо two.py запустить two.sh вот такого содержания:
#!/bin/sh
i=0
while true ; do
i=`expr $i + 1`
echo "iteration #$i`seq -s '+' 1012 | sed 's/[0-9]//g'`"
sleep 1
done
То увидите такую же картинку, как и при запуске two.py с python -u.
Понятно ли?

PS: Под ‘запустить’ я имею в виду это:
p=subprocess.Popen(['/bin/sh','./two.sh'], stdout=subprocess.PIPE, bufsize=0)
Ed
И, чтобы уж совсем было понятно, посмотрите сюда: http://hg.python.org/cpython/file/fd6446a88fe3/Modules/main.c
Поищите там по setbuf или setvbuf и увидите, что Питону(/usr/bin/python) все равно, что вы там поставили при вызове subprocess.Popen. Он назначает либо не назначает буфер для stdout в зависимости от параметра командной строки -u.
o7412369815963
> Питону(/usr/bin/python) все равно, что вы там поставили при вызове subprocess.Popen
я про то и написал в последнем сообщении
JOHN_16
>я про то и написал в последнем сообщении
как то уж совсем видимо завуалированно.

Ed спасибо за подсказку с -u, совсем забыл про ключи самого интерпретатора.

Выходит что параметр bufsize это всего лишь обманка? которая есть и в python2 и в python3 при этом также упоминается в официальной документации. Не красиво как то получается, вводит людей в заблуждение
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