はじめに
自分の環境だけでしょうか。
Pythonスクリプトで、標準(エラー)出力をファイルにしたり、他のPythonスクリプトから実行した時、出力のタイミングがおかしい。
printやsys.stdout.writeを実行したタイミングではなく、プロセスが終了した時点で一気に出てきてる。
ファイルに書いてみる
出力タイミングがおかしいスクリプト
実行したPythonスクリプトはこれ。1秒おきに数字を出すだけ。
child1.py
from time import sleep
for i in range(10):
print(str(i))
sleep(1)
これを下記コマンドで実行すると、何も出力されず、10秒経過後に一気にログが出る。
$ python3 ./child1.py > stdout.log & tail -f stdout.log
修正版
次に修正版。printの後にsys.stdout.flushを実行してみる。
child2.py
from time import sleep
import sys
for i in range(10):
print(str(i))
sys.stdout.flush()
sleep(1)
同様に下記コマンドで実行すると、1秒おきに出力される。
$ python3 ./child2.py > stdout.log & tail -f stdout.log
ちなみに、
$ python3 ./child1.py
と、画面に出力する分には問題なく出力される。
別のPythonスクリプトから呼び出す
親スクリプトとしては、ここに掲載されていたものを使わせてもらった。
parent.py
import sys
import subprocess
def get_lines(cmd):
'''
:param cmd: str 実行するコマンド.
:rtype: generator
:return: 標準出力 (行毎).
'''
proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
while True:
line = proc.stdout.readline()
if line:
yield line.decode('utf-8')
if not line and proc.poll() is not None:
break
if __name__ == '__main__':
for line in get_lines(cmd='python3 ./child1.py'): # ./child2.pyを実行すると1秒おきに出力される
sys.stdout.write(line)
これだと画面に出力するときでも、child1.pyは10秒後に一気に出力され、child2.pyは1秒おきに出力される
結論
そういうもんなんかな?
→そういうもんらしいです。
(追記)
下記コメントでの指摘の通り、python3コマンド実行時に-uオプションをつければ随時出力されることが確認できました。また一つ賢くなりました。
# 「できなかった」系も書いてみるもんですね。