Найти - Пользователи
Полная версия: stdin, stdout и каналы
Начало » Python для новичков » stdin, stdout и каналы
1
koluna
Всем привет!

Объясните, пожалуйста, как работают stdin, stdout при выполнении подобной команды в терминале:
prog1.py | prog2.exe

В какой момент вывод prog1 попадает на ввод prog2?
Только при завершении prog1?
Есть ли различия для Linux и Windows?
JOHN_16
prog1.py в течении своей работы посылает строки на стандартный поток вывода (sys.stdout) которые операционной системой хранятся в специальном буфере. По завершении работы процесса запускается процесс prog2.exe на стандартный поток которого передается содержание буфера.
Таким образом передается только цельный фрагмент данных, нельзя организовать таким образом передачу информации кусочками.
Насколько я знаю в Windows и linux это работает идентично.
Однако в UNIX системах существуют UNIX Domain Socket - сокеты для межпроцессного взаимодействия. Их, пожалуй, главное отличие от каналов в возможности дву направленного обмена сообщениями, синхронно и асинхронно
py.user.next
koluna
Объясните, пожалуйста, как работают stdin, stdout при выполнении подобной команды в терминале:
Ну, как у python есть три потока, так и у prog2.exe есть три потока. Поток вывода python соединяется с потоком ввода prog2.exe. (Программа python пишет в то же место, откуда читает prog2.exe.)

koluna
В какой момент вывод prog1 попадает на ввод prog2?
С момента запуска.

koluna
Есть ли различия для Linux и Windows?
В данном случае нет.


JOHN_16
По завершении работы процесса запускается процесс prog2.exe на стандартный поток которого передается содержание буфера.
Нет, они сразу оба запускаются и всё, что успевает вывестись из первой программы, сразу передаётся во вторую.

[guest@localhost ~]$ python3 -c 'print(1); input(); print(2)' | cat -n
1 1
x
2 2
[guest@localhost ~]$
JOHN_16
py.user.next
Таки да. Был не прав в своих суждениях. Все дело в буферизации вывода. Пример в linux:
#one.py
import time
for i in xrange(5):
    print 'I can do it, i will print value {}'.format(i)
    time.sleep(1)
При вызове получится что вывод отобразиться сразу, а не постепенно.
python one.py  | tee 
Если изменить исходный код так, что бы принудительно высвобождать буферы вывода:
import time, sys
for i in xrange(5):
    print 'I can do it, i will print value {}'.format(i)
    sys.stdout.flush()
    time.sleep(1)
…то вывод получится построчно.
Если мы просто организуем много вывода, то увидим работу буферизации в действии:
import time, sys
for i in xrange(500):
    print 'I can do it, i will print value {}'.format(i)
    time.sleep(0.01)

В общем признаю свою не правоту, работа с маленькими кодами сыграла со мной шутку.
py.user.next
JOHN_16
Все дело в буферизации вывода.

C89 (draft) 4.9.3
   At program startup, three text streams are predefined and need not
be opened explicitly --- standard input (for reading conventional
input), standard output (for writing conventional output), and
standard error (for writing diagnostic output). When opened, the
standard error stream is not fully buffered; the standard input and
standard output streams are fully buffered if and only if the stream
can be determined not to refer to an interactive device.

Сделал программу:
#include <stdio.h>
#include <unistd.h>

int main(void)
{
int i;

for (i = 0; i < 3; i++) {
printf("Test %d\n", i);
sleep(1);
}
return 0;
}

Этот выводит построчно:
[guest@localhost c]$ .ansi t.c -o t
[guest@localhost c]$ ./t
Test 0
Test 1
Test 2
[guest@localhost c]$

Этот выводит всё сразу:
[guest@localhost c]$ ./t | cat -n
1 Test 0
2 Test 1
3 Test 2
[guest@localhost c]$

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

Аналогично и здесь:
[guest@localhost ~]$ python3 -c 'import time; print(1); time.sleep(2); print(2)'
1
2
[guest@localhost ~]$ python3 -c 'import time; print(1); time.sleep(2); print(2)' | cat -n
1 1
2 2
[guest@localhost ~]$
В первом случае - построчно, во втором - сразу всё.
koluna
По поводу того, что процессы работают параллельно и данные передаются постоянно - понятно, спасибо за разъяснения.

Какой размер буферов stdin, stdout по умолчанию?
Можно ли изменить размер буфера и получить информацию о количестве символов в нем?
Что происходит, когда буфер stdin переполняется или близок к этому? Читал, что процесс слева от ‘|’ приостанавливается операционной системой, пока процесс справа от ‘|’ не вычитает все данные (по крайней мере для Линукс).
Не понятно, может ли буфер переполниться и потеряются ли данные или нет?
py.user.next
koluna
Какой размер буферов stdin, stdout по умолчанию?
BUFSIZ - платформозависимая константа, 8 килобайт.

koluna
Можно ли изменить размер буфера и получить информацию о количестве символов в нем?
Если тебе это понадобилось в питоне, то что-то не так делаешь. В C есть функции для изменения не только размера, но и адреса.

koluna
Что происходит, когда буфер stdin переполняется или близок к этому?
Содержимое выталкивается и буфер делается пустым.

koluna
Читал, что процесс слева от ‘|’ приостанавливается операционной системой, пока процесс справа от ‘|’ не вычитает все данные
Ну, наверняка блокируется для вывода, пока читатель не прочитает.

koluna
Не понятно, может ли буфер переполниться и потеряются ли данные или нет?
Функции вывода следят за его размером. Если там есть место, они дописывают, если нет - вызывают выталкивание и обнуление и пишут в пустой.
Обычно данные не теряются, потому что буферы выталкиваются при нормальном завершении программы. При аварийном завершении могут не вытолкнуться.
koluna
Т. е., если программы работают нормально, то данные при обмене между программами через stdout-stdin не теряются?
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