[解決済み] V8でこのコードスニペットを使用すると、なぜ<=は<より遅いのですか?
質問
スライドを読んでいるところ
V8でJavascriptの速度制限を突破する
以下のような例があります。なぜ
<=
よりも遅いです。
<
この場合、どなたか説明できる方はいらっしゃいますか?何かコメントがあれば、よろしくお願いします。
遅い。
this.isPrimeDivisible = function(candidate) {
for (var i = 1; i <= this.prime_count; ++i) {
if (candidate % this.primes[i] == 0) return true;
}
return false;
}
(ヒント:primesはprime_countの長さの配列です。)
もっと早く
this.isPrimeDivisible = function(candidate) {
for (var i = 1; i < this.prime_count; ++i) {
if (candidate % this.primes[i] == 0) return true;
}
return false;
}
[詳細情報] の速度向上は顕著で、私のローカル環境でのテストでは、以下のような結果でした。
V8 version 7.3.0 (candidate)
遅い。
time d8 prime.js
287107
12.71 user
0.05 system
0:12.84 elapsed
もっと早く
time d8 prime.js
287107
1.82 user
0.01 system
0:01.84 elapsed
解決方法は?
私はGoogleでV8を担当していますが、既存の回答やコメントに加え、さらにいくつかの洞察を提供したいと思います。
参考までに、以下がそのコード例です。 スライド :
var iterations = 25000;
function Primes() {
this.prime_count = 0;
this.primes = new Array(iterations);
this.getPrimeCount = function() { return this.prime_count; }
this.getPrime = function(i) { return this.primes[i]; }
this.addPrime = function(i) {
this.primes[this.prime_count++] = i;
}
this.isPrimeDivisible = function(candidate) {
for (var i = 1; i <= this.prime_count; ++i) {
if ((candidate % this.primes[i]) == 0) return true;
}
return false;
}
};
function main() {
var p = new Primes();
var c = 1;
while (p.getPrimeCount() < iterations) {
if (!p.isPrimeDivisible(c)) {
p.addPrime(c);
}
c++;
}
console.log(p.getPrime(p.getPrimeCount() - 1));
}
main();
まず何よりも、性能差は関係ありません。
<
と
<=
演算子を直接使用することができます。そのため
<=
Stack Overflowで遅いという記事を読んだからというのが理由ですが、そんなことはありません。
次に、配列が "holey"であることを指摘する人がいました。これはOPの投稿にあるコード・スニペットでは明確ではありませんでしたが、以下の初期化コードを見ていただければ一目瞭然です。
this.primes
:
this.primes = new Array(iterations);
この結果、配列には
a
HOLEY
要素の種類
V8では、たとえ配列が完全に埋まる/詰まる/連続することになったとしても、です。一般に、穴のあいた配列に対する操作は、詰められた配列に対する操作よりも遅くなりますが、この場合、その差はごくわずかで、1 Smi を追加する程度です (
小整数
を打つたびに(穴を防ぐための)チェックを行います。
this.primes[i]
の中のループで
isPrimeDivisible
. 大したことはありません。
TL;DR
である配列は
HOLEY
は、ここでは問題ではありません。
他の方から、コードが圏外に読まれているとのご指摘をいただきました。一般に、以下のように推奨されています。 配列の長さを超えて読み込まないようにする この場合、確かにパフォーマンスの大幅な低下は避けられたはずです。しかし、なぜでしょうか? V8は、これらのアウトオブバウンドのシナリオのいくつかを、パフォーマンスにわずかな影響を与えるだけで処理することができます。 では、この特殊なケースは何が特別なのでしょうか?
アウトオブバウンズの読み取りは
this.primes[i]
あり
undefined
をこの行に追加します。
if ((candidate % this.primes[i]) == 0) return true;
そして、その結果、次のようになります。
本当の問題
:
%
演算子が非整数のオペランドで使われるようになったのです!
-
integer % someOtherInteger
は非常に効率的に計算することができます。JavaScriptエンジンはこのような場合に高度に最適化された機械語コードを生成することができます。 -
integer % undefined
一方、この方法ではFloat64Mod
というのはundefined
はdoubleで表現される。
このコードは、確かに
<=
を
<
をこの行に追加してください。
for (var i = 1; i <= this.prime_count; ++i) {
...ではなく
<=
よりも優れた演算子です。
<
が、この特殊なケースで境界外読出しを回避できるというだけの理由です。
関連
-
vueネットワークリクエストソリューション ネイティブネットワークリクエストとjsネットワークリクエストライブラリ
-
[解決済み】React - uncaught TypeError: 未定義のプロパティ 'setState' を読み取れない
-
[解決済み] テスト
-
[解決済み] 期待される代入または関数呼び出し: 未使用式なし ReactJS
-
モジュールのビルドに失敗しました。Error: ENOENT: no such file or directory, scandir 'D:\.... \node_modules
-
[解決済み] 私のJavaScriptコードは "No 'Access-Control-Allow-Origin' header is present on requested resource "というエラーを受け取りますが、Postmanはそうならないのはなぜですか?
-
[解決済み] 配列の反復処理に "for...in "を使用するのは、なぜ良くないのでしょうか?
-
[解決済み] 関数内で変数を変更した後、変数が変更されないのはなぜですか?- 非同期コードリファレンス
-
[解決済み] なぜJavaScriptのeval関数を使うとダメなのか?
-
[解決済み] AngularJS : なぜangularでは{{}}よりもng-bindが良いのですか?
最新
-
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 実装 サイバーパンク風ボタン
おすすめ
-
vueネットワークリクエストソリューション ネイティブネットワークリクエストとjsネットワークリクエストライブラリ
-
要素ツリー制御によるvueTreeテーブル
-
HTML+CSS+JavaScriptで簡単な三目並べゲームを作成する。
-
vue for 登録ページ効果 vue for sms 認証コードログイン
-
[解決済み】Node.js getaddrinfo ENOTFOUND
-
[解決済み】TypeError: Router.use() はミドルウェアの関数を要求しているが、Object を取得した。
-
[解決済み】 Uncaught TypeError : undefined のプロパティ 'replace' を読み取れない In Grid
-
フロントエンド非同期(アシンク)ソリューション(全ソリューション)
-
JSクリックイベント - Uncaught TypeError: プロパティ 'onclick' に null を設定できません。
-
OSSアップロードエラーを解決する: net::ERR_SSL_PROTOCOL_ERROR