Уведомления

Группа в Telegram: @pythonsu

#1 Июнь 16, 2011 15:09:38

JOHN_16
От: Россия, Петропавловск-Камчатск
Зарегистрирован: 2010-03-22
Сообщения: 3292
Репутация: +  221  -
Профиль   Отправить e-mail  

bufsize в subprocess.Popen - баг или фича ? Давайте разберемся.

Итак, задача: вызвать интерпретатор, передать ему имя файла для исполнения, по ходу его выполнения перехватывать вывод. Т.о. есть программа 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)



_________________________________________________________________________________
полезный блог о python john16blog.blogspot.com

Офлайн

#2 Июнь 16, 2011 16:48:17

Ed
От:
Зарегистрирован: 2008-12-13
Сообщения: 1032
Репутация: +  13  -
Профиль   Отправить e-mail  

bufsize в subprocess.Popen - баг или фича ? Давайте разберемся.

Это Питон буферизирует. Попробуйте .



Офлайн

#3 Июнь 16, 2011 16:55:25

Андрей Светлов
От:
Зарегистрирован: 2007-05-15
Сообщения: 3137
Репутация: +  14  -
Профиль   Адрес электронной почты  

bufsize в subprocess.Popen - баг или фича ? Давайте разберемся.

В two.py делайте sys.stdout.flush() после каждого sys.stdout.write(s).
one.py менять не нужно.



Офлайн

#4 Июнь 16, 2011 17:57:04

Ed
От:
Зарегистрирован: 2008-12-13
Сообщения: 1032
Репутация: +  13  -
Профиль   Отправить e-mail  

bufsize в subprocess.Popen - баг или фича ? Давайте разберемся.

Андрей Светлов
В two.py делайте sys.stdout.flush() после каждого sys.stdout.write(s).
one.py менять не нужно.
Это он знает. В первом посте упоминалось.



Офлайн

#5 Июнь 16, 2011 18:54:36

o7412369815963
От:
Зарегистрирован: 2009-06-17
Сообщения: 1986
Репутация: +  32  -
Профиль   Отправить e-mail  

bufsize в subprocess.Popen - баг или фича ? Давайте разберемся.

Офлайн

#6 Июнь 16, 2011 19:02:32

o7412369815963
От:
Зарегистрирован: 2009-06-17
Сообщения: 1986
Репутация: +  32  -
Профиль   Отправить e-mail  

bufsize в subprocess.Popen - баг или фича ? Давайте разберемся.

возможно так!?:
bufsize регулирует буферизацию one.py (при приеме), но у two.py есть свой буфер (при отдаче).

Офлайн

#7 Июнь 16, 2011 21:18:19

Ed
От:
Зарегистрирован: 2008-12-13
Сообщения: 1032
Репутация: +  13  -
Профиль   Отправить e-mail  

bufsize в subprocess.Popen - баг или фича ? Давайте разберемся.

Вы меня видимо не поняли. Попробую пояснить на примере.
Если вместо 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)



Отредактировано (Июнь 16, 2011 21:21:36)

Офлайн

#8 Июнь 16, 2011 21:34:50

Ed
От:
Зарегистрирован: 2008-12-13
Сообщения: 1032
Репутация: +  13  -
Профиль   Отправить e-mail  

bufsize в subprocess.Popen - баг или фича ? Давайте разберемся.

И, чтобы уж совсем было понятно, посмотрите сюда: http://hg.python.org/cpython/file/fd6446a88fe3/Modules/main.c
Поищите там по setbuf или setvbuf и увидите, что Питону(/usr/bin/python) все равно, что вы там поставили при вызове subprocess.Popen. Он назначает либо не назначает буфер для stdout в зависимости от параметра командной строки -u.



Офлайн

#9 Июнь 16, 2011 22:04:01

o7412369815963
От:
Зарегистрирован: 2009-06-17
Сообщения: 1986
Репутация: +  32  -
Профиль   Отправить e-mail  

bufsize в subprocess.Popen - баг или фича ? Давайте разберемся.

> Питону(/usr/bin/python) все равно, что вы там поставили при вызове subprocess.Popen
я про то и написал в последнем сообщении

Офлайн

#10 Июнь 16, 2011 23:40:59

JOHN_16
От: Россия, Петропавловск-Камчатск
Зарегистрирован: 2010-03-22
Сообщения: 3292
Репутация: +  221  -
Профиль   Отправить e-mail  

bufsize в subprocess.Popen - баг или фича ? Давайте разберемся.

>я про то и написал в последнем сообщении
как то уж совсем видимо завуалированно.

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

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



_________________________________________________________________________________
полезный блог о python john16blog.blogspot.com

Офлайн

Board footer

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

Powered by DjangoBB

Lo-Fi Version