8

サブプロセスの stdout パイプから出力を取得する際に問題が発生しています。ログ出力を抽出するために、それを介してサードパーティのコードを起動しています。サードパーティのコードが最近更新されるまでは、すべて正常に機能していました。更新後、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()
4

2 に答える 2

6

まず、この例を単純化して、実際に何でも読めるようにすることをお勧めします。ミックスからスレッドの複雑さを取り除きます。

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()
于 2012-05-02T01:37:17.317 に答える
1
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()

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

于 2012-09-07T05:55:19.713 に答える