他のアプローチと比較して、このスクリプトが非常に効率的である理由は何ですか?
著者がこのアルゴリズムに対して行っているいくつかの最適化があります。これらのそれぞれについて、基盤となるメカニズム (Javascript、CPU、レジスター、キャッシュ、ビデオ カードなど) がどのように利用されているかをかなり深く理解する必要があります。彼が行っている重要な最適化は 2 つあると思います (残りは単なるアイシングです)。
- 出力のバッファリング
- 文字列操作ではなく整数演算を使用する
バッファリングについて明示的に質問されたので、すぐにバッファリングについて説明します。彼が利用している整数演算には、パフォーマンス上の利点が 2 つあります。整数の加算は、文字列操作よりも 1 回の操作あたりのコストが低く、使用するメモリも少なくなります。
JavaScript と Web ブラウザーがブラウザーで整数から表示グリフへの変換をどのように処理するかはわかりません。そのため、整数を document.write に渡すと、文字列と比較した場合にペナルティが生じる可能性があります。ただし、彼は (1,000,000 / 1000) の document.write 呼び出しと 1,000,000 - 1,000 の整数の追加を実行しています。これは、メッセージをディスプレイに送信する操作よりも、メッセージを形成する操作の方が約 3 桁多いことを意味します。したがって、整数と文字列を document.write に送信する際のペナルティは、3 桁を超える必要があり、整数を操作することによるパフォーマンス上の利点が相殺されます。
バッファリングによって速度が上がるのはなぜですか?
動作する理由の詳細は、使用しているプラットフォーム、ハードウェア、および実装によって異なります。いずれにせよ、ボトルネックを誘発するリソースに対してアルゴリズムのバランスを取ることがすべてです。
たとえば、ファイル I/O の場合、バッファは、回転するディスクが一度に特定の量しか書き込めないという事実を利用するため、役立ちます。作業が少なすぎると、ディスクが回転するときにスピンドルのヘッドの下を通過するすべての利用可能なビットを使用できなくなります。与えすぎると、アプリケーションは、ディスクが書き込みを完了するまで待機する (またはスリープ状態にする) 必要があります。次のレコードを書き込み準備するために費やすことができる時間です! ファイル I/O の理想的なバッファー サイズを決定する主な要因には、セクター サイズ、ファイル システムのチャンク サイズ、インターリーブ、ヘッド数、回転速度、面密度などがあります。
CPU の場合は、パイプラインをフルに保つことがすべてです。CPU に与える作業が少なすぎると、CPU はタスクを待つ間、NO OP のスピンに時間を費やすことになります。CPU に負荷をかけすぎると、ディスクやビデオ カードなど、並行して実行できる他のリソースに要求をディスパッチできなくなる可能性があります。これは、後で CPU が何もせずにこれらが返されるのを待たなければならないことを意味します。CPU でのバッファリングの主な要因は、(CPU に) 必要なものすべてを FPU/ALU のできるだけ近くに保持することです。典型的なアーキテクチャでは、これは (近い順に) レジスタ、L1 キャッシュ、L2 キャッシュ、L3 キャッシュ、RAM です。
100 万の数字を画面に書き込む場合は、ビデオ カードを使用して画面に多角形を描画することです。このように考えてみてください。追加された新しい数値ごとに、ビデオ カードは画面にポリゴンを描画するために 100,000,000 回の操作を行う必要があるとします。極端な例として、一度に 1 つの数値をページに書き込み、それをビデオ カードに書き出させ、これを 1,000,000 の数値に対して行うと、ビデオ カードは 10^14 の操作、つまり 100 兆の操作を実行する必要があります。反対に、100 万個の数字全体を一度にビデオ カードに送信した場合、1 億回の操作しか必要ありません。最適なポイントは、中間のどこかです。一度に 1 回実行すると、CPU が 1 つの作業単位を実行し、GPU がディスプレイを更新する間、長時間待機します。
使用するバッファ サイズをどのように決定しますか?
特定のアルゴリズム (インターネット ルーティング用のパケット ルーティングを記述するなど) を使用して、非常に具体的で明確に定義されたプラットフォームを対象としていない限り、通常、これを数学的に決定することはできません。通常、経験的に見つけます。値を推測して試し、結果を記録してから、別の値を選択します。管理しているボトルネックに基づいて、どこから開始し、どの範囲を調査するかについて、経験に基づいた推測を行うことができます。
このスクリプトをさらに最適化するための秘訣を知っている人はいますか?
これが機能するかどうかはわかりませんが、テストしていませんが、コンピューターのアンダーピニングはバイナリであり、ワードサイズは通常2 の倍数 (ただし、常にそうとは限りません!)。たとえば、64 バイトは 60 バイトよりも最適である可能性が高く、1024 は 1000 よりも最適である可能性が高くなります。に注意してください) 残りの Web ページ レンダリング メカニズムと同じスレッド内で、javascript をシリアルに実行します。これは、javascript が何らかの作業を行ってバッファを埋め、その後 document.write 呼び出しが戻るまで長時間待機することを意味します。Chrome のように、javascript が別のプロセスとして非同期に実行された場合、速度が大幅に向上する可能性があります。もちろん、これはボトルネックを使用するアルゴリズムではなく、ボトルネックの原因を攻撃することですが、それが最善の選択肢である場合もあります。
私が望むほど簡潔ではありませんが、良い出発点になることを願っています。バッファリングは、コンピューティングにおけるあらゆる種類のパフォーマンスの問題にとって重要な概念です。コードが使用している基本的なメカニズム (ハードウェアとソフトウェアの両方) を十分に理解することは、パフォーマンスの問題を回避または対処するのに非常に役立ちます。