2009-09-11 11 views
12

Mam ogólne pytanie o popen (i wszystkie powiązane funkcje), mające zastosowanie do wszystkich systemów operacyjnych, kiedy piszę skrypt Pythona lub jakiś kod c i uruchamiam wynikowy plik wynikowy z konsola (wygrana lub linux), natychmiast widzę wyjście z procesu. Jeśli jednak uruchomię ten sam plik wykonywalny jako proces rozwidlony, a jego standardowe wyjście zostanie przekierowane do potoku, dane wyjściowe będą buforowane gdzieś, zwykle do 4096 bajtów, zanim zostaną zapisane do potoku, gdzie proces nadrzędny może go odczytać.Pomijanie buforowania wyjścia podprocesowego z popen w C lub Pythonie

Poniższy skrypt Pythona będzie generować dane wyjściowe w kawałki 1024 bajtów

import os, sys, time 

if __name__ == "__main__": 
    dye = '@'*1024 
    for i in range (0,8): 
     print dye 
     time.sleep(1) 

Poniższy skrypt Pythona wykona poprzedni skrypt i odczytać dane wyjściowe tak szybko, jak to jest do rury, bajt po bajcie

import os, sys, subprocess, time, thread 

if __name__ == "__main__": 
    execArgs = ["c:\\python25\\python.exe", "C:\\Scripts\\PythonScratch\\byte_stream.py"] 

    p = subprocess.Popen(execArgs, bufsize=0, stdout=subprocess.PIPE) 
    while p.returncode == None: 
     data = p.stdout.read(1) 
     sys.stdout.write(data) 
     p.poll() 

Dostosuj ścieżkę do systemu operacyjnego. Po uruchomieniu w tej konfiguracji dane wyjściowe nie będą wyświetlane w porcjach o rozmiarze 1024, ale o rozmiarze 4096, mimo że rozmiar bufora polecenia popen jest ustawiony na 0 (co jest domyślne). Czy ktoś może mi powiedzieć, jak zmienić to zachowanie ?, czy jest jakiś sposób zmusić system operacyjny do traktowania wyjścia z rozwidlonego procesu w taki sam sposób, jak przy uruchamianiu z konsoli ?, tj. Po prostu przesłać dane przez bez buforowania?

Odpowiedz

14

Ogólnie rzecz biorąc, standardowa biblioteka środowiska wykonawczego C (działająca w imieniu niemal każdego programu w każdym systemie, mniej więcej ;-), wykrywa, czy stdout jest terminalem czy nie; jeśli nie, buforuje wyjście (co może być ogromną wygraną efektywności w porównaniu z niebuforowanym wyjściem).

Jeśli masz kontrolę nad programem, który wykonuje ten tekst, możesz (jak sugerowała inna odpowiedź) nieprzerwanie przepuszczać stdout lub (bardziej elegancko, jeśli to możliwe), próbować wymusić stdout jako niebuforowany, np. uruchamiając Python z flagą -u poleceń:

-u  : unbuffered binary stdout and stderr (also PYTHONUNBUFFERED=x) 
     see man page for details on internal buffering relating to '-u' 

(co dodaje strona man jest wzmianka o stdin i problemów z trybie binarnym [s]).

Jeśli nie możesz lub nie chcesz dotykać programu, który piszesz, -u lub podobnego w programie, który jest po prostu czytanie jest mało prawdopodobne, aby pomóc (buforowanie, które ma największe znaczenie jest to, co dzieje się na stdout pisarza, nie ten na stdin czytnika). Alternatywą jest nakłonienie pisarza do przekonania, że ​​pisze on do terminala (mimo że w rzeczywistości pisze do innego programu!), Za pośrednictwem standardowego modułu bibliotecznego lub wyższego poziomu modułu strony trzeciej pexpect (lub, dla systemu Windows, jego port wexpect).

+0

próbowałem grać z -u, bez radości, ale pexpect wydaje się obiecujący, dziękuję! –

+0

tylko po to, aby kontynuować, pexpect działa jak czar, wexpect jest trochę kłopotliwy (i trudny do znalezienia), ale wykonuje swoją robotę. Właśnie tam znalazłem najnowszą wersję Wexpect: http://sage.math.washington.edu/home/goreckc/sage/wexpect/ –

+0

Dzięki Gearoid, co ciekawe, wexpect nie został zaktualizowany do najnowszej wersji W domu code.google.com zastanawiam się, dlaczego! –

1

To jest poprawne i dotyczy zarówno systemu Windows, jak i Linux (i prawdopodobnie innych systemów), z popen() i fopen(). Jeśli chcesz, aby bufor wyjściowy był wysyłany przed 4096 bajtów, użyj fflush() (on C) lub sys.stdout.flush() (Python).

+0

Tak, właśnie to robię w tej chwili, ale moja sytuacja robocza oznacza, że ​​proces generujący wynik jest zdefiniowany przez użytkownika, powinienem wspomnieć, że w początkowym pytaniu –