2012-05-02 20 views
5

私は、サブプロセスのstdoutパイプから出力を得ることにいくつかの困難を抱えています。私はログ出力を抽出するために、それを介していくつかの第三者コードを起動しています。サードパーティのコードが最近更新されるまで、すべて正常に機能しました。更新後、pythonは無期限にブロックを開始し、実際に出力を表示しません。私は手動でサードパーティのアプリを正常に起動し、出力を見ることができます。Windowsの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使用することはできません。私が立ち上げているアプリは長時間(数日から数週間)実行されています。私が実際に試すことができる唯一の方法は、起動した直後にアプリを殺すことです。私はそれが私に有効な結果を与えるとは思わないのです。

この失敗したのであっても非スレッドバージョン:

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() 

それがうまくいくならば。次に、あなたが直接stdoutを読んでいるかどうか、おそらくあなたのスレッドに問題がある可能性があります。

これが機能しない場合は、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文字ずつゆっくりと1秒ごとに印刷されているということですが、サードパーティのアプリケーションがどのような出力をしているのか分かりません。バッファーからデッドロックする可能性があります。また、このような問題が発生した場合は、可能な限り多くの変数を削除し、各ステップが正しく機能することを確認することをお勧めします。 – 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() 
...です

このファイルはスレッド、一時ファイルの魔法ではなく動作するはずです。

関連する問題