# Python の `-u` オプションを用いて stdout と stderr のバッファを行わないようにする Python内で新しい子プロセスを立ち上げる時に、Pythonの `subprocess` モジュールを用いることで、子プロセスを良い感じに抽象化して扱うことができます。例えば以下のコードでは、Bashスクリプトを子プロセスで実行し、その子プロセスの標準出力を文字列として受け取っています。ここで注目して欲しいのは、`asyncio` を用いて、標準出力をインタラクティブに受け取れることです。1秒ごとに、インクリメントされた数値が表示されます。 ```:python cmd = 'for i in `seq 1 5`; do echo $i; sleep 1; done' proc = await asyncio.create_subprocess_shell( cmd, stdout=asyncio.subprocess.PIPE) async for data in proc.stdout: line = data.decode('ascii').rstrip() print(line) ```  ここで、BashではなくPythonの子プロセスを立ち上げて結果を受け取ってみようと考え、以下のコードを作成しました。 ```:python cmd = \ 'python -c "' + \ 'import time\n' + \ 'for i in range(5): print(i); time.sleep(1)"' proc = await asyncio.create_subprocess_shell( cmd, stdout=asyncio.subprocess.PIPE) async for data in proc.stdout: line = data.decode('ascii').rstrip() print(line) ```  いざこのプログラムを実行してみると、期待通りの結果が得られませんでした。最初に示したプログラムでは1秒毎に数値が表示されていましたが、上記プログラムを実行すると、最初5秒間は何も表示されず、5秒後に全ての結果が一気に表示されてしまいました。 色々試してみましたが、Pythonプログラムに変更を加えても、インタラクティブに結果を受け取ることはできませんでした。挙動を見る限り、どこかに文字列がバッファされているようだったので、もしや Python のランタイムが怪しいのではと思いググると、あっさり問題は解決しました。 PythonのCLIツールには、`-u` オプションというものがあります。`-u` オプションは、Pythonのランタイムに stdout と stderr のバッファをさせるかどうかを決めるオプションです。デフォルトでは、バッファをするようになっているため、このオプションをつけることでバッファをしないようにします。 `-u` オプションを追記した以下のプログラムでは、期待通りにインタラクティブな結果を得ることができました。よかった。 ```:python cmd = \ 'python -u -c "' + \ 'import time\n' + \ 'for i in range(5): print(i); time.sleep(1)"' proc = await asyncio.create_subprocess_shell( cmd, stdout=asyncio.subprocess.PIPE) async for data in proc.stdout: line = data.decode('ascii').rstrip() print(line) ```  今回は表面的な調査しかしていませんが、また時間があれば Python ランタイムでどのようにバッファが行われているのか、調査してみたいです。 ## 参考文献 - [Python: significance of -u option? - stack overflow](https://stackoverflow.com/questions/14258500/python-significance-of-u-option) ## コード全文 ```:python import asyncio import sys async def run(): cmd = \ 'python -u -c "' + \ 'import time\n' + \ 'for i in range(5): print(i); time.sleep(1)"' proc = await asyncio.create_subprocess_shell( cmd, stdout=asyncio.subprocess.PIPE) async for data in proc.stdout: line = data.decode('ascii').rstrip() print(line) await proc.wait() asyncio.run(run()) ```
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up