ループが繰り返しのprintステートメントでデバッグされると、当初の予想よりもはるかにプログラムの速度が低下するため、この質問をします。私はこれに慣れてきましたが、なぜこれが当てはまるのかという技術的な理由に興味がありますか?変数のさまざまな計算と割り当ては、文字列を出力するよりもコストがかかるように思われます。
3 に答える
かなりの数ですが、もう 1 つの重要な (または最も重要な) ボトルネックは、CPU とは関係ありません: I/O オーバーヘッドです。バイトコード命令がディスパッチされ、すべての引数が文字列に変換されると、それらの文字列を に書き込む関数が呼び出されますsys.stdout
。システムとプログラムの実行方法に応じて、次のようになります。
- ディスク上のファイル
- 端末エミュレータからのパイプ
- 出力をキャプチャするいくつかの Python オブジェクト (これは IDLE が IIRC を実行する方法です) を実行して、誰が何を実行するか (キャプチャ、GUI への配置など) を行います。
ケース #1 では、ディスク I/O が関係しており、RAM への書き込みよりも桁違いに遅くなります。そして、RAM は現在の CPU に比べてすでに非常に遅いです。コメントに記載されているように、これは OS と Python による大規模なバッファリングによる問題ではありませんが、書き込みを発行するのにまだ時間がかかります (実装の詳細によっては、私はあまり知りません) まだ時間がかかる場合があります。誰かがバッファを時期尚早にフラッシュした場合の時間。
#2の場合、すべてがメモリに残りますが、それはまだシステムコールであり、いくつかのコピーであり、反対側はそれを読み取って、気付くために何かを行う必要があります(たとえば、アンチ複雑なタスクであるエイリアス フォント)。同時に発生する可能性があるため問題は少ないですが、それでも CPU に負荷がかかります。
ケース #3 では、すべての賭けが無効になります。出力を bcrypt でハッシュし、月に送信する可能性があります。たまたまIDLEを使用していますか?IDLE の出力のリダイレクトが非常に遅い(でしょうか?) という苦情を思い出しました。出力をキャプチャし、これまでの出力と連結して、Tkinter にレンダリングさせる必要があります。
特に、最新のマルチタスク システムのターミナル エミュレーター ウィンドウなど、出力が画面に表示される場合は、非常に大きな、非常に大きな数です。
まず、数値を 10 進数で出力している場合、各桁に divmod があります。これは、加算などに比べて比較的高価な操作です。(16 進数で出力する場合は、シフトとマスキングのみを使用して各桁を抽出できるため、少し安くなる可能性があります。) 浮動小数点数を出力する場合は、さらに計算が必要になります。日付と時刻については、考慮すべきさまざまな長さの月、うるう年、うるう秒、DST、およびタイムゾーンのすべてがあります。
しかし、それはすべて単なる計算と論理であるため、今後のことを考えると小さくなります。
次に、Python は表示のために出力テキストを端末に送信する必要があります。つまり、オペレーティング システムは、バッファを介してデータを転送し、他のプロセスを起動する必要があります。端末プロセスは、入力をスキャンして制御シーケンスを探し、カーソルを移動したり、色を変更したりします。次に、テキスト レンダラーがテキストをスキャンして、特別な処理が必要な文字を探します。適用するアクセント記号の組み合わせや、表示のために再配置する必要がある右から左へのスクリプトがある可能性があります。
テキストがレイアウトされると、ターミナルはウィンドウ マネージャーにウィンドウのどの領域を再描画する必要があるかを伝え、ウィンドウ マネージャーはそれが表示されているかどうかを確認します。端末は、実際に描画が必要な領域を通知され、最終的に適切なフォントと色、カーニングとアンチエイリアスでテキストを描画します。ウィンドウの背景が透明になっていてかっこいいですか? これも統合する必要があります。
ウィンドウ システムによっては、ピクセルは、オペレーティング システムのバッファーを介して、ウィンドウの透明度を考慮して、実際にウィンドウの内容を画面に描画する合成マネージャーに到達する可能性があります。
最後に、ピクセルが画面に表示されます。出力ストリーミングが速すぎて読めないため、数百万の後継者によって一掃される前に、ピクセルが表示される時間はほとんどありません。
私たちのコンピューターが私たちのためにどれだけの仕事をしているかは驚くべきことです。
これは CPU 命令の問題ではなく、少なくとも Python プログラムの CPU 命令の問題ではありません。端末エミュレータ (コマンド ウィンドウ) を出力として使用するprint
と、出力される文字列がカーネル バッファにコピーされ、次に端末プロセスのメモリにコピーされます。オーバーヘッドは、コンテキストの切り替え (両方のプロセスがシステム コールを実行する、つまりカーネル モードにジャンプする) とメモリ内の文字列のコピーにあります。