私はいつも、printステートメントで端末に出力するのにかかる時間に驚かされたりイライラしたりしてきました。最近の痛々しいほど遅いロギングの後、私はそれを調べることにしました、そして、費やされたほとんどすべての時間が端末が結果を処理するのを待っているのを見つけて非常に驚きました。
stdoutへの書き込みをなんとかスピードアップできますか?
print_timer.py
stdout、ファイル、およびstdoutにリダイレクトされた100k行を書き込むときのタイミングを比較するために、スクリプト(この質問の下部にある' ')を作成しました/dev/null
。タイミングの結果は次のとおりです。
$ python print_timer.py
this is a test
this is a test
<snipped 99997 lines>
this is a test
-----
timing summary (100k lines each)
-----
print :11.950 s
write to file (+ fsync) : 0.122 s
print with stdout = /dev/null : 0.050 s
わお。stdoutを/dev/ nullなどに再割り当てしたことを認識するなど、Pythonが舞台裏で何かを行っていないことを確認するために、スクリプトの外部でリダイレクトを行いました...
$ python print_timer.py > /dev/null
-----
timing summary (100k lines each)
-----
print : 0.053 s
write to file (+fsync) : 0.108 s
print with stdout = /dev/null : 0.045 s
つまり、これはPythonのトリックではなく、単なる端末です。私はいつも/dev/ nullに出力をダンプすることで物事がスピードアップすることを知っていましたが、それがそれほど重要であるとは思いもしませんでした!
ttyがどれほど遅いかは私を驚かせます。物理ディスクへの書き込みが「画面」(おそらくすべてRAM操作)への書き込みよりもはるかに高速であり、/ dev / nullを使用してガベージにダンプするのと同じくらい効果的に高速であるのはどうしてですか?
このリンクでは、端末がI / Oをブロックして、「[入力]の解析、フレームバッファーの更新、ウィンドウをスクロールするためのXサーバーとの通信など」を行う方法について説明しています...しかし、私はしません完全にそれを取得します。何がそんなに時間がかかるのでしょうか?
(より高速なtty実装がないのですか?)解決策はないと思いますが、とにかく質問したいと思います。
更新:いくつかのコメントを読んだ後、私は自分の画面サイズが実際に印刷時間にどの程度の影響を与えるのか疑問に思いました、そしてそれはいくつかの重要性を持っています。上記の非常に遅い数値は、私のGnomeターミナルが1920x1200まで膨らんだ状態です。小さくすると非常に小さくなります...
-----
timing summary (100k lines each)
-----
print : 2.920 s
write to file (+fsync) : 0.121 s
print with stdout = /dev/null : 0.048 s
それは確かに良いです(〜4x)が、私の質問は変わりません。ターミナル画面のレンダリングによってアプリケーションのstdoutへの書き込みが遅くなる理由がわからないため、これは私の質問に追加されるだけです。プログラムが画面レンダリングの続行を待つ必要があるのはなぜですか?
すべてのターミナル/ttyアプリが同じように作成されていませんか?私はまだ実験していません。端末はすべての着信データをバッファリングし、それを目に見えない形で解析/レンダリングし、現在の画面構成に表示されている最新のチャンクのみを適切なフレームレートでレンダリングできる必要があるように思えます。したがって、ディスクへの書き込み+ fsyncを約0.1秒で実行できる場合、端末は同じ操作をその順序で完了できるはずです(実行中に画面が数回更新される可能性があります)。
プログラマーにとってこの動作を改善するために、アプリケーション側から変更できるtty設定があることを私はまだ望んでいます。これが厳密にターミナルアプリケーションの問題である場合、これはStackOverflowに属していない可能性がありますか?
私は何が欠けていますか?
タイミングを生成するために使用されるPythonプログラムは次のとおりです。
import time, sys, tty
import os
lineCount = 100000
line = "this is a test"
summary = ""
cmd = "print"
startTime_s = time.time()
for x in range(lineCount):
print line
t = time.time() - startTime_s
summary += "%-30s:%6.3f s\n" % (cmd, t)
#Add a newline to match line outputs above...
line += "\n"
cmd = "write to file (+fsync)"
fp = file("out.txt", "w")
startTime_s = time.time()
for x in range(lineCount):
fp.write(line)
os.fsync(fp.fileno())
t = time.time() - startTime_s
summary += "%-30s:%6.3f s\n" % (cmd, t)
cmd = "print with stdout = /dev/null"
sys.stdout = file(os.devnull, "w")
startTime_s = time.time()
for x in range(lineCount):
fp.write(line)
t = time.time() - startTime_s
summary += "%-30s:%6.3f s\n" % (cmd, t)
print >> sys.stderr, "-----"
print >> sys.stderr, "timing summary (100k lines each)"
print >> sys.stderr, "-----"
print >> sys.stderr, summary