9

私はベンチマーク サイトjfprefsをいじっていて、 http: //jsperf.com/prefix-or-postfix-increment/9で独自のベンチマークを作成しました。

ベンチマークは、前置インクリメンタと後置インクリメンタを使用し、インプレース インクリメンタを使用しない Crockford jslint スタイルを使用した Javascript for ループのバリエーションです。

for (var index = 0, len = data.length; index < len; ++index) {
  data[index] = data[index] * 2;
}

for (var index = 0, len = data.length; index < len; index++) {
  data[index] = data[index] * 2;
}

for (var index = 0, len = data.length; index < len; index += 1) {
  data[index] = data[index] * 2;
}

ベンチマークを数回実行して数値を取得した後、Firefox は平均して 1 秒あたり約 15 回の操作を実行し、Chrome は約 300 回の操作を実行していることに気付きました。

ベンチマーク結果

JaegerMonkey と v8 は、速度の点でかなり匹敵すると思いましたか? 私のベンチマークには何らかの欠陥がありますか、Firefox はここで何らかのスロットリングを行っていますか、それとも Javascript インタープリターのパフォーマンスのギャップは本当に大きいのでしょうか?

更新: jfriend00のおかげで、このバージョンのテストケースに見られるように、パフォーマンスの違いはループの繰り返しによるものではないと結論付けました。ご覧のとおり、Firefox の方が遅いですが、最初のテスト ケースで見たほどの差はありません。

では、なぜその声明は、

data[index] = data[index] * 2;

Firefox ではそんなに遅いですか?

4

2 に答える 2

8

JavaScript では配列はトリッキーです。それらを作成する方法、それらを埋める方法 (およびどの値を使用するか) はすべて、パフォーマンスに影響を与える可能性があります。

エンジンが使用する 2 つの基本的な実装があります。最も単純で最も明白なものは、メモリの連続したブロックです (C 配列のように、長さなどのメタデータを持ちます)。これは最速の方法であり、理想的にはほとんどの場合に必要な実装です。

問題は、JavaScript の配列が任意のインデックスに割り当てるだけで非常に大きくなり、「穴」が残ることです。たとえば、小さな配列がある場合:

var array = [1,2,3];

そして、大きなインデックスに値を割り当てます:

array[1000000] = 4;

次のような配列になります。

[1, 2, 3, undefined, undefined, undefined, ..., undefined, 4]

メモリを節約するために、ほとんどのランタイムはarray「スパース」配列に変換されます。基本的には、通常の JS オブジェクトと同様のハッシュ テーブルです。これが発生すると、インデックスへの読み取りまたは書き込みは、単純なポインター演算から、おそらく動的メモリ割り当てを使用する、はるかに複雑なアルゴリズムになります。

もちろん、異なるランタイムは異なるヒューリスティックを使用して、ある実装から別の実装にいつ変換するかを決定します。そのため、場合によっては、たとえば Chrome 向けに最適化すると、Firefox のパフォーマンスが低下する可能性があります。

あなたの場合、私の最善の推測は、配列を逆方向に埋めると、Firefoxが疎な配列を使用し、速度が低下することです。

于 2012-09-08T23:57:39.883 に答える
-5

私はあなたにそのような単純な答えを与えるのは嫌いですが、非常に単純です: 命令の分岐: http://igoro.com/archive/fast-and-slow-if-statements-branch-prediction-in-modern-processors/

ベンチマークから得た情報によると、これらのエンジンの内部には、プロセッサーに地獄のような命令予測機能を提供する何かがあります。

于 2012-09-08T06:03:29.960 に答える