LoginSignup
5
8

More than 5 years have passed since last update.

Pythonで標準(エラー)出力をファイルにすると出力タイミングがおかしい

Last updated at Posted at 2017-03-02

はじめに

自分の環境だけでしょうか。

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オプションをつければ随時出力されることが確認できました。また一つ賢くなりました。
# 「できなかった」系も書いてみるもんですね。

5
8
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
8