2012-05-02 4 views
5

Występują pewne trudności z uzyskaniem wyniku z potoku podprocesowego podprocesowego. Uruchamiam za jego pośrednictwem jakiś kod strony trzeciej, aby wyodrębnić dane wyjściowe dziennika. Aż do ostatniej aktualizacji kodu strony trzeciej wszystko działało dobrze. Po aktualizacji python zaczął blokować w nieskończoność i nie wyświetlał żadnych danych wyjściowych. Mogę ręcznie uruchomić aplikację firmową w porządku i zobaczyć dane wyjściowe.Wyjście podprocesu Python w systemie Windows?

Podstawowa wersja kodu używam:

import subprocess, time 
from threading import Thread 

def enqueue_output(out): 
    print "Hello from enqueue_output" 
    for line in iter(out.readline,''): 
     line = line.rstrip("\r\n") 
     print "Got %s" % line 
    out.close() 

proc = subprocess.Popen("third_party.exe", stdout=subprocess.PIPE, bufsize=1) 
thread = Thread(target=enqueue_output, args=(proc.stdout,)) 
thread.daemon = True 
thread.start() 

time.sleep(30) 

Działa to doskonale, jeśli zastąpić third_party.exe dla tego skryptu:

import time, sys 

while True: 
    print "Test" 
    sys.stdout.flush() 
    time.sleep(1) 

więc jestem jasne, magii należy zrobić, aby działało to z oryginalnym poleceniem.

Są to wszystkie warianty linii subprocess.Popen próbowałem bez powodzenia:

proc = subprocess.Popen("third_party.exe", stdout=subprocess.PIPE, bufsize=0) 
proc = subprocess.Popen("third_party.exe", stdout=subprocess.PIPE, shell=True) 
proc = subprocess.Popen("third_party.exe", stdout=subprocess.PIPE, creationflags=subprocess.CREATE_NEW_CONSOLE) 
si = subprocess.STARTUPINFO() 
si.dwFlags = subprocess.STARTF_USESTDHANDLES | subprocess.STARTF_USESHOWWINDOW 
proc = subprocess.Popen("third_party.exe", stdout=subprocess.PIPE, startupinfo=si) 

Edit 1: nie mogę faktycznie korzysta .communicate() w tym przypadku. Uruchomiona przeze mnie aplikacja działa przez długie okresy czasu (dni lub tygodnie). Jedynym sposobem, w jaki mogłem przetestować .communicate() byłoby zabicie aplikacji wkrótce po jej uruchomieniu, co nie wydaje mi się, że dałoby to prawidłowe wyniki.

Nawet niegwintowane wersja to się nie powiedzie:

import subprocess, time 
from threading import Thread 

proc = subprocess.Popen("third_party.exe", stdout=subprocess.PIPE, stderr=subprocess.PIPE) 

print "App started, reading output..." 
for line in iter(proc.stdout.readline,''): 
    line = line.rstrip("\r\n") 
    print "Got: %s" % line 

Edycja 2: Dzięki JDI następujące prace okay:

import tempfile, time, subprocess 

w = "test.txt" 
f = open("test.txt","a") 
p = subprocess.Popen("third_party.exe", shell=True, stdout=f, 
         stderr=subprocess.STDOUT, bufsize=0) 

time.sleep(30) 

with open("test.txt", 'r') as r: 
    for line in r: 
     print line 
f.close() 
+0

Czy jest możliwe, że Twój program zewnętrzny został przełączony na zapisywanie na stderr? – jdi

+0

Nie wydaje się, że tak jest. Jeśli zamiast tego przechwycę stderr, stanie się to samo (chociaż widzę wyjście aplikacji na konsoli, ale to tylko drukowanie, nie przechodzi Python). – devicenull

+0

Wygląda na to, że aplikacja przestała używać standardowego wyjścia i pisze bezpośrednio na konsoli. Jeśli tak, niewiele można z tym zrobić. Czy możesz sprawdzić u sprzedawcy aplikacji? –

Odpowiedz

5

Pierwszy Polecam że uprościć ten przykład aby upewnić się, że rzeczywiście możesz przeczytać cokolwiek. Usuń komplikacje wątku z miksu:

proc = subprocess.Popen("third_party.exe", stdout=subprocess.PIPE, bufsize=1) 
print proc.communicate() 

Jeśli to działa, świetnie. Wtedy masz problemy z tym, jak czytasz stdout bezpośrednio lub ewentualnie w swoim wątku.

Jeśli to nie działa, czy próbowałeś również wypróbować stderr na stdout?

proc = subprocess.Popen("third_party.exe", 
         stdout=subprocess.PIPE, 
         stderr=subprocess.STDOUT, bufsize=1) 

Aktualizacja

Skoro mówisz communicate() jest deadlocking, tutaj jest inne podejście można spróbować sprawdzić, czy jest to problem z wewnętrznym buforze podproces ...

import tempfile 
import subprocess 

w = tempfile.NamedTemporaryFile() 
p = subprocess.Popen('third_party.exe', shell=True, stdout=w, 
         stderr=subprocess.STDOUT, bufsize=0) 

with open(w.name, 'r') as r: 
    for line in r: 
     print line 
w.close() 
+0

Jeśli wystąpił błąd w wątku, dlaczego miałby on działać w mojej prostej aplikacji testowej, ale nie w rzeczywistości? Nie mogę używać komunikacji, ponieważ aplikacja tak naprawdę się nie kończy. To serwer i działa przez długi czas. – devicenull

+0

@devicenull: Powiedziałbym, że różnica polega na tym, że twój skrypt testowy drukuje 4 znaki, powoli, co sekundę, podczas gdy ja nie mam pojęcia, jaki rodzaj wyjścia robi twoja aplikacja innej firmy. Możesz zablokować z bufora. Ponadto, gdy masz takie problemy, zawsze najlepiej usuń jak najwięcej zmiennych i upewnij się, że każdy krok działa poprawnie. – jdi

+0

Przesyłanie do pliku działa idealnie. Jakieś pomysły, dlaczego tak działa, ale rury nie? – devicenull

2
args = ['svn','log','-v'] 

def foo(info=''): 
    import logging 
    import subprocess 
    import tempfile 
    try: 
     pipe = subprocess.Popen(args,bufsize = 0,\ 
      stdout = subprocess.PIPE,\ 
      stderr=subprocess.STDOUT) 
    except Exception as e: 
     logging.error(str(e)) 
     return False 
    while 1: 
     s = pipe.stdout.read() 
     if s: 
      print s, 
     if pipe.returncode is None: 
      pipe.poll() 
     else: 
      break 
    if not 0 == pipe.returncode: 
     return False 
    return True 

print foo() 

Ten powinien działać, a nie gwintować, magiczne pliki tymczasowe.