私はいつも、printステートメントを使用して端末に出力するのにかかる時間に驚かされ、不満を感じてきました。最近痛々しいほど遅いロギングの後で、私はそれを調査することに決めました、そして費やされたほとんどすべての時間は端末が結果を処理するのを待っていることを発見してかなり驚きました。
stdoutへの書き込みをどうにかして高速化できますか?
print_timer.py
100k行をstdout、file、およびstdoutにリダイレクトして書き込むときのタイミングを比較するスクリプト(この質問の最後にある' ')を書きました/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
それは確かに優れています(約4倍)が、私の質問は変わりません。端末画面のレンダリングでアプリケーションがstdoutへの書き込みを遅くする理由がわからないため、私の質問に追加されるだけです。スクリーンレンダリングが続行するのをプログラムが待機する必要があるのはなぜですか?
すべての端末/ ttyアプリが同じではありませんか?まだ実験していない。端末はすべての着信データをバッファリングし、不可視に解析/レンダリングし、現在の画面構成に表示される最新のチャンクのみを適切なフレームレートでレンダリングできるように思われます。したがって、ディスクに〜0.1秒で+ fsyncを書き込むことができれば、端末は同じ操作をその順序で完了することができるはずです(実行中にいくつかの画面が更新される可能性があります)。
プログラマにとってこの動作をより良くするためにアプリケーション側から変更できる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