2012-05-02 111 views
5

我遇到了一些困難,從子流程標準輸出管道獲取輸出。我正在通過它啓動一些第三方代碼,以提取日誌輸出。直到最近更新的第三方代碼,一切正常。更新之後,python已經無限期地開始阻塞,並且沒有實際顯示任何輸出。我可以手動啓動第三方應用程序並查看輸出。窗口上的Python子流程輸出?

我正在使用的代碼的基本版本:

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) 

這工作完全,如果我代替third_party.exe這個腳本:

import time, sys 

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

所以我不清楚魔需要完成這項工作才能使用原始命令。

這些都是我沒有成功嘗試subprocess.Popen線的所有變體:

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) 

編輯1: 我實際上並不能在這種情況下使用.communicate()。我啓動的應用程序仍在運行很長一段時間(幾天到幾周)。我實際上可以測試.communicate()的唯一方法就是在啓動後不久就殺死該應用程序,我不覺得會給我有效的結果。

即使這個非線程版本失敗:

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 

編輯2: 由於JDI,以下的作品沒關係:

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

是否有可能您的第三方程序切換到寫入stderr? – jdi

+0

似乎並非如此。如果我攔截stderr,則會發生同樣的情況(儘管如此,我確實在控制檯上看到了應用程序的輸出,但它只是打印,不會通過Python)。 – devicenull

+0

聽起來好像應用程序已停止使用標準輸出並直接寫入控制檯。如果是這樣,你可以做的不多。你能檢查應用程序的供應商嗎? –

回答

5

首先,我會建議您簡化此示例確保你可以真正閱讀任何東西。從混合中刪除線程的複雜性:

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

如果這樣的話,很好。然後,您可能會直接或者可能在線程中讀取標準輸出。

如果這不起作用,你有沒有嘗試將stderr管道輸出到stdout呢?

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

更新

既然你說communicate()被死鎖,這裏是另一種方法,你可以嘗試看看,如果它與子進程的內部緩衝區問題...

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

如果我在線程出現錯誤,爲什麼它可以用於我的簡單測試應用程序,但不是真實的東西?我無法使用溝通,因爲應用程序實際上並沒有結束。它是一臺服務器,並且長時間保持運行。 – devicenull

+0

@devicenull:我會說不同之處在於,您的測試腳本每秒都會慢慢地打印4個字符,而我不知道您的第三方應用程序正在執行何種輸出。你可能會從緩衝區中死鎖。而且,當你有這樣的問題時,它總是儘可能地去除儘可能多的變量,並確保每一步都能正常工作。 – jdi

+0

輸出到一個文件完美。任何想法,爲什麼工作,但管道不? – 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() 

這一個應該工作,而不是線程,臨時文件魔術。

相關問題