ここでの答えはどれも私のニーズのすべてに対応していません。
- stdoutのスレッドはありません(キューなどもありません)
- 進行中の他のことを確認する必要があるため、ノンブロッキング
- ストリーム出力、ログファイルへの書き込み、出力の文字列コピーの返送など、複数のことを実行するために必要なPIPEを使用します。
少し背景:私はThreadPoolExecutorを使用してスレッドのプールを管理し、それぞれがサブプロセスを起動して並行処理を実行しています。(Python2.7では、これは新しい3.xでも機能するはずです)。他のもののために可能な限り多くを利用したいので、出力収集のためだけにスレッドを使用したくありません(20プロセスのプールは、実行するためだけに40スレッドを使用します;プロセススレッド用に1つ、標準出力用に1つ...そして、もしあなたが私が推測するstderrが欲しいなら)
ここでは多くの例外などを取り除いているので、これは本番環境で機能するコードに基づいています。うまくいけば、私はコピーアンドペーストでそれを台無しにしていない。また、フィードバックは大歓迎です!
import time
import fcntl
import subprocess
import time
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
# Make stdout non-blocking when using read/readline
proc_stdout = proc.stdout
fl = fcntl.fcntl(proc_stdout, fcntl.F_GETFL)
fcntl.fcntl(proc_stdout, fcntl.F_SETFL, fl | os.O_NONBLOCK)
def handle_stdout(proc_stream, my_buffer, echo_streams=True, log_file=None):
"""A little inline function to handle the stdout business. """
# fcntl makes readline non-blocking so it raises an IOError when empty
try:
for s in iter(proc_stream.readline, ''): # replace '' with b'' for Python 3
my_buffer.append(s)
if echo_streams:
sys.stdout.write(s)
if log_file:
log_file.write(s)
except IOError:
pass
# The main loop while subprocess is running
stdout_parts = []
while proc.poll() is None:
handle_stdout(proc_stdout, stdout_parts)
# ...Check for other things here...
# For example, check a multiprocessor.Value('b') to proc.kill()
time.sleep(0.01)
# Not sure if this is needed, but run it again just to be sure we got it all?
handle_stdout(proc_stdout, stdout_parts)
stdout_str = "".join(stdout_parts) # Just to demo
ここにオーバーヘッドが追加されることは確かですが、私の場合は問題になりません。機能的には、私が必要とすることを行います。私が解決していない唯一のことは、これがログメッセージに対して完全に機能する理由ですが、一部のprint
メッセージが後で一度にすべて表示されるのがわかります。