-108

条件演算子===と代入演算子=のパフォーマンスに違いはありますか? 私はマングースでいくつかの事前保存フックミドルウェアを書いていますが、次の間に速度の違いがあるかどうか疑問に思っています:

UserSchema.pre('save', function (next) {
    if (!this.isModified()) {
        return next();
    }
    this.crm.isUpToDate = false;
    next();
});

UserSchema.pre('save', function (next) {
    if (!this.isModified()) {
        return next();
    }
    if (this.crm.update === true) {
        this.crm.isUpToDate = false;
    }
    next();
});

編集:

建設的なコメントをありがとう。

基本的に、パフォーマンスに大きな違いがあるようには見えません (上記のように無視できます)。速度をテストするためのクールなツールhttp://jsperf.com/に感謝します。これまで聞いたことがありませんでした。

コードについて疑問に思っている人のために、最初に最初の投稿で露骨な間違いを犯し、それからみんながそれを指摘しようとしたとき、私は泣きました。

これが私がやっていることです:

ドキュメントが保存されるたびにフックが実行される mongoose pre-save ミドルウェア フック (mongo データベース用) があります。保存の時点で、ドキュメントが更新されたかどうかを確認します。もしそうなら、私はcrmIsUpToDatefalse に設定しました。crmIsUpToDatecron ジョブが取得されると、true に設定されます。このフックは、cron ジョブがドキュメントに到達する前に何度でも実行できます。

===質問は比較を行うことと代入を行うことの間に違いがあるかどうかだったので、これが質問に必要なすべてだとは思いませんでした=。主な質問から本当に損なったので、コードを掲載するべきではありませんでした。

4

2 に答える 2

51

非 refcounting 言語 (JavaScript はそうではありません) を使用していて、大きなオブジェクトの代入 ('='、結果としてコピー操作が行われます) を実行すると、「遅く」なる可能性があります。そのため、そのコピー操作が本当に必要かどうかを確認することで、時間を大幅に節約できます。

しかし、JavaScript はネイティブの参照カウント言語です。

object1 = {a: 1, b: 2};
object2 = object1;         // refcounting copy?
object1.a = 3;             // test by modifying the first object
console.log( object2.a );  // will return 3 => refcounting

=> したがって、すべての代入操作 ('=') は非常に安価です。

さらに、ネイティブ データ型 (bool、数値は同じ) を使用しているため、オブジェクトよりも高速であるか、少なくともオブジェクトと同じくらい高速である可能性があります。
注: 文字列は JavaScript では参照カウントされません。この場合は例外です。

それで、今、私たちは割り当てが安いことを学びました. しかし、ID チェック (「===」) はどうでしょうか?

コードでは、オブジェクトを通り抜ける必要がありますthis-> crm-> update- これにはさらに時間がかかります。次に、型 (bool) の同一性をチェックし、内容 (false) が同じかどうかをチェックする必要があります。
これらはすべて、長いパイプラインを備えた最新の CPU が分岐を誤って推測し、完全なパイプラインのストールとリロードを引き起こす可能性があるプログラム フローに条件を追加しています。これはまた、非常に多くの CPU サイクルを浪費します (ただし、最新の CPU はこれに非常に優れています)。

=> この比較 ('===') は非常にコストがかかります。

結論 #1:
簡単に回避できる高価なテストで安価なコードを保護するべきではありません。
コードがより高価になると、最終的にテストが時間を節約するポイントが来ます。これはにつながります:

結論 #2:
時期尚早の最適化は悪です! コードを読みにくくしたり、新しいバグを導入したり、コードを大きくしたり (キャッシュ効率も悪い)、...
=> パフォーマンスの問題で実行していると確信しているコードの部分のみを最適化します。プロファイリング情報に基づいています。人間はここでの影響を推測するのがかなり苦手です...

于 2014-07-12T10:19:30.687 に答える
8

現在の最上位の回答は、重要な点で間違っています。オブジェクトを深く比較しないため、===と同様に安価です。=メモリ内の同じオブジェクトを参照しているかどうかを確認するだけです。(ifブランチはここで唯一の本当の犯人です)

===条件演算子と代入演算子のパフォーマンスに違いはあります=か?

===は条件演算子ではありません - ===「厳密等価比較」(または「同一性」または「厳密等価」) です。(Javascript の条件演算子の形式はcondition ? expr1 : expr2)

での割り当てが非常に安価であることは既に説明しましたvarName = expression。基本的に、expressionメモリ内の場所をvarName取得し、その場所もポイントします。expressionが巨大なオブジェクトであっても、ディープ コピーは発生しません。

しかし、ほとんどの場合、Strict Equality Comparison についても同じことが当てはまります。次のいずれかの場合expr1 === expr2に評価されます。true

  1. 両方の式がプリミティブであり、両方が同じ型と同じ値 ( を除くNaN) である、または

  2. どちらの式もオブジェクトであり、オブジェクトはメモリ内の同じオブジェクトです。

2 つのオブジェクト式がメモリ内の同じオブジェクトを参照しているかどうかをチェックするのは、非常にコストがかかりません。オブジェクトのメモリ参照を取得し、変数がそのメモリ位置を指すようにするのと同じ程度です (=そうです)。ネストされたすべてのプロパティと値を深く比較するわけではありません (の両側を ing する===ようなもので明示的に比較しない限り、しかしその場合、ボトルネックはではなくです)JSON.stringify===JSON.stringify===

ifブランチのあるコード:

if (this.crm.update === true) {
    this.crm.isUpToDate = false;
}

単純な割り当てよりも遅くなります:

this.crm.isUpToDate = false;

論理分岐が(比較的)遅いため。===チェックと=割り当ては非常に高速です。

一般的な経験則として、分岐は直線コードよりも遅くなります (すべての CPU で、すべてのプログラミング言語で)。- jmrk、V8 開発者

これは、有名な質問の背後にある同じ問題です:並べ替えられた配列を処理する方が、並べ替えられていない配列よりも速いのはなぜですか?

とはいえ、論理分岐には追加のリソースが必要ですが、最新のコンピューターではその影響が重要になることはめったにありません。きれいで読みやすいコードを目指して努力し、そのセクションがパフォーマンスを引き起こしていることを確認してから、そのようなセクションの変更を検討することをお勧めします。そうしないと、コードが読みにくくなり、多くの場合、わずかな違いになります。

于 2019-04-03T01:40:54.620 に答える