サブプロセスモジュールを次のように使用したいと思います。
stdout
(またはstderr
、あるいは両方、一緒にまたは別々に)Popenでプロセスを作成しましたが、communicate()を使用すると、プロセスが終了すると、データが一度に届きます。
_myprocess.stdout
_のreadline()
をブロックする別のスレッドを作成すると(_stdout = subprocess.PIPE
_を使用)、プロセスが終了するまで、このメソッドでも行を取得できません。 (bufsizeとして何を設定しても)
恐ろしくなく、複数のプラットフォームでうまく機能するこれに対処する方法はありますか?
動作しないように見えるコードで更新します(とにかくWindowsで)
class ThreadWorker(threading.Thread):
def __init__(self, callable, *args, **kwargs):
super(ThreadWorker, self).__init__()
self.callable = callable
self.args = args
self.kwargs = kwargs
self.setDaemon(True)
def run(self):
try:
self.callable(*self.args, **self.kwargs)
except wx.PyDeadObjectError:
pass
except Exception, e:
print e
if __== "__main__":
import os
from subprocess import Popen, PIPE
def worker(pipe):
while True:
line = pipe.readline()
if line == '': break
else: print line
proc = Popen("python subprocess_test.py", Shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE)
stdout_worker = ThreadWorker(worker, proc.stdout)
stderr_worker = ThreadWorker(worker, proc.stderr)
stdout_worker.start()
stderr_worker.start()
while True: pass
stdoutはバッファリングされるため、そのバッファがいっぱいになるか、サブプロセスが終了するまで、何も取得されません。
サブプロセスからstdout
をフラッシュするか、stderrを使用するか、非バッファモードでstdoutを変更してみてください。
これが私のために働いたものです:
_cmd = ["./tester_script.bash"]
p = subprocess.Popen( cmd, Shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE )
while p.poll() is None:
out = p.stdout.readline()
do_something_with( out, err )
_
あなたの場合、サブプロセスへの参照をワーカースレッドに渡して、スレッド内でポーリングを実行することができます。 2つのスレッドが同じサブプロセスをポーリング(および相互作用)したときにどのように動作するかはわかりませんが、機能する可能性があります。
また、while p.poll() is None:
は現状のままであることに注意してください。実行not python _0
_(正常終了のリターンコード)もFalse
と見なされるように、while not p.poll()
に置き換えます。
問題は、サブプロセスによるバッファリングされた出力の使用にあるようです。比較的少量の出力が作成された場合、サブプロセスが終了するまでバッファリングされる可能性があります。いくつかの背景を見つけることができます ここ :
一度に1文字ずつ読んでください: http://blog.thelinuxkid.com/2013/06/get-python-subprocess-output-without.html
import contextlib
import subprocess
# Unix, Windows and old Macintosh end-of-line
newlines = ['\n', '\r\n', '\r']
def unbuffered(proc, stream='stdout'):
stream = getattr(proc, stream)
with contextlib.closing(stream):
while True:
out = []
last = stream.read(1)
# Don't loop forever
if last == '' and proc.poll() is not None:
break
while last not in newlines:
# Don't loop forever
if last == '' and proc.poll() is not None:
break
out.append(last)
last = stream.read(1)
out = ''.join(out)
yield out
def example():
cmd = ['ls', '-l', '/']
proc = subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
# Make all end-of-lines '\n'
universal_newlines=True,
)
for line in unbuffered(proc):
print line
example()
Pexpect [ http://www.noah.org/wiki/Pexpect] を非ブロッキングreadlineで使用すると、この問題が解決します。これは、パイプがバッファリングされているため、アプリの出力がパイプによってバッファリングされているため、バッファがいっぱいになるかプロセスが終了するまでその出力に到達できません。
私もこの問題に遭遇しています。 stderrも読み取ろうとしているため、問題が発生します。エラーがない場合、stderrから読み取ろうとするとブロックされます。
Windowsでは、ファイル記述子をpoll()する簡単な方法はありません(Winsockソケットのみ)。
したがって、解決策はstderrから読み取ろうとしないことです。
これはよく知られているPythonの制限、 PEP 3145 および多分他のものを参照してください。
Subprocess.Popenを使用して、C#プロジェクトの1つの.exeを実行し、出力をPythonファイルにリダイレクトできます。すべての情報をprint()
できるようになりました。 (Console.WriteLine()
を使用して)C#コンソールからPythonコンソールに出力されます。
Pythonコード:
from subprocess import Popen, PIPE, STDOUT
p = Popen('ConsoleDataImporter.exe', stdout = PIPE, stderr = STDOUT, Shell = True)
while True:
line = p.stdout.readline()
print(line)
if not line:
break
これにより、作成時に.NETプロジェクトのコンソール出力が1行ずつ取得され、プロジェクトの終了時に囲んでいるwhileループから抜け出します。これは2つのpythonファイルでも機能すると思います。
私はこれにpexpectモジュールを使用しましたが、問題なく動作しているようです。 http://sourceforge.net/projects/pexpect/