[解決済み] 標準出力への印刷が遅いのはなぜですか?速くすることはできますか?
質問
printステートメントでターミナルに出力するだけでも時間がかかるので、いつも驚いたり、イライラしたりしています。 最近、ロギングがひどく遅くなったので、それを調べることにしました。 すべて は、ターミナルが結果を処理するのを待つために費やされる時間です。
stdoutへの書き込みを何とか早くできないか?
スクリプトを書きました('
print_timer.py
にリダイレクトした場合、ファイルに書き込んだ場合、標準出力に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
すげーな。 pythonが裏でstdoutを/dev/nullに再割り当てしたことを認識するとか、そういうことをやっていないことを確認するために、スクリプトの外でリダイレクトを行いました...。
$ 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の実装がない限り)、とにかく聞いてみようと思いました。
UPDATE: いくつかのコメントを読んだ後、画面サイズが印刷時間に実際にどの程度影響するのか疑問に思っていました。 上の本当に遅い数字は、私の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倍)、私の疑問は変わりません。 それはただ 追加 というのも、なぜ端末の画面レンダリングが、標準出力に書き込むアプリケーションの速度を落とすのかがわからないからです。 なぜ、私のプログラムは画面描画を待つ必要があるのでしょうか?
すべてのターミナル/ttyアプリが同じように作られているわけではないのでしょうか? 私はまだ実験していません。 ターミナルは、すべての受信データをバッファリングし、目に見えないように解析/レンダリングし、現在の画面構成で表示されている最新のチャンクのみを適切なフレームレートでレンダリングできる必要があるように思います。 つまり、私がディスクへの書き込みと同期を 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
解決方法は?
たくさんのコメントありがとうございました。 結局、皆さんに助けていただきながら自分で回答しています。 自分の質問に自分で答えるのは汚い気がしますが。
質問1:stdoutへの印刷が遅いのはなぜですか?
回答 stdoutへのプリントは ではない 本質的に遅いのです。 遅いのは、あなたが作業する端末の方です。 そして、アプリケーション側のI/Oバッファリング(例:Pythonのファイルバッファリング)とはほとんど関係がありません。 以下を参照してください。
疑問2:高速化できるのか?
回答 しかし、プログラム側(標準出力に「印刷」する側)から見ると、そうではないようです。 高速化するには、より高速な別の端末エミュレータを使用してください。
説明...
という自称「軽量」な端末プログラムを試してみました。
wterm
となり
かなり
より良い結果を得ることができます。 以下は、私のテストスクリプト(質問の最下部)で実行したときの出力です。
wterm
で、1920x1200 で、gnome-terminal を使って基本的な印刷オプションで12秒かかったのと同じシステムで、です。
----- タイミングサマリ(各100k行) ----- 印刷:0.261秒 ファイルへの書き込み(+fsync) : 0.110 s 標準出力 = /dev/null での印刷 : 0.050 秒
0.26sは12sよりMUCH良い! 私は
wterm
は、私が提案した方法(妥当なフレームレートで「見える」尾部をレンダリングする)に沿って、画面へのレンダリング方法についてより知的であるか、あるいは、単に
gnome-terminal
. 私の質問の目的のために、私は答えを持っている、しかし。
gnome-terminal
は遅い。
ですから、もしあなたが長時間実行するスクリプトが遅いと感じていて、標準出力に大量のテキストを吐き出しているなら、別のターミナルを試してみて、少しでも良くなるかどうか見てみてください
なお、私はかなりランダムに
wterm
をubuntu/debianのレポジトリから取得しました。
このリンク
は、同じターミナルかもしれませんが、よくわかりません。 他のターミナルエミュレータはテストしていません。
更新:かゆいところに手が届くということで、同じスクリプトでフルスクリーン(1920x1200)にして他の端末エミュレータを一通りテストしてみました。 手動で収集した統計はここにあります。
wterm 0.3s aterm 0.3秒 rxvt 0.3秒 mrxvt 0.4秒 コンソール 0.6秒 yakuake 0.7秒 lxterminal 7秒 xterm 9s gnome-ターミナル 12秒 xfce4-ターミナル 12s ヴァラ端子 18秒 xvt 48s
記録されたタイムは手動で収集したものですが、かなり安定していました。 ベストな値を記録しました。 もちろん、YMMVです。
また、様々な端末エミュレータを体験することができ、とても興味深いものでした。 私の最初の「代替」テストが、この中で一番良いものになったことに驚いています。
関連
-
ピローによる動的キャプチャ認識のためのPythonサンプルコード
-
[解決済み】TypeErrorの修正方法。Unicodeオブジェクトは、ハッシュ化する前にエンコードする必要がある?
-
[解決済み] Pythonで辞書に新しいキーを追加するにはどうすればよいですか?
-
[解決済み] 割り当て後にリストが予期せず変更されました。その理由と防止策を教えてください。
-
[解決済み] ワイルドカードマッチングに基づいて、現在のフォルダとサブフォルダ内のすべてのファイルを再帰的に検索するにはどうすればよいですか?
-
[解決済み] Linux上で動作するC++コードのプロファイリングを行うにはどうすればよいですか?
-
[解決済み] print関数の出力をフラッシュする(pythonの出力をバッファリング解除する)にはどうすればよいですか?
-
[解決済み] 出力をファイルや標準出力にリダイレクトする方法
-
[解決済み] 標準出力ではなく標準エラー出力にパイプを通すにはどうしたらいいですか?
-
[解決済み】ネストされたディレクトリを安全に作成するには?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
PicgoのイメージベッドツールをPythonで実装する
-
Python カメの描画コマンドとその例
-
PythonはWordの読み書きの変更操作を実装している
-
Python 可視化 big_screen ライブラリ サンプル 詳細
-
PythonによるExcelファイルの一括操作の説明
-
[解決済み】Python regex AttributeError: 'NoneType' オブジェクトに 'group' 属性がない。
-
[解決済み】pygame.error: ビデオシステムが初期化されていない
-
[解決済み】Python: SyntaxError: キーワードは式になり得ない
-
[解決済み】NameError: 名前 'self' が定義されていません。
-
[解決済み] ファイルに行を書き込む正しい方法?