2

命令の最適化について質問があります。オブジェクトが 2 つのステートメントで使用される場合、新しいオブジェクト参照を作成する方が速いですか、それとも両方のステートメントでオブジェクトを直接呼び出す必要がありますか?

私の質問の目的のために、オブジェクトはオブジェクトの一部Vectorです (この例は、ArrayLists のない合理化されたバージョンの Java からのものです)。次に例を示します。

AutoEvent ptr = ((AutoEvent)e_autoSequence.elementAt(currentEventIndex));
if(ptr.exitConditionMet()) {currentEventIndex++; return;}
ptr.registerSingleEvent();

AutoEventは問題のクラスで、e_autoSequenceAutoEventVectorオブジェクトの です。問題のAutoEvent2 つのメソッドが含まれています:exitConditionMet()registerSingleEvent()

したがって、このコードは次のように書くこともできます。

if(((AutoEvent)e_autoSequence.elementAt(currentEventIndex)).exitConditionMet()) 
    {currentEventIndex++; return;}
((AutoEvent)e_autoSequence.elementAt(currentEventIndex)).registerSingleEvent();

これは上記よりも高速ですか?

キャスト プロセスが遅いことは理解しているので、この質問は実際には 2 つあります。さらに、オブジェクトをキャストしていない場合、どちらがより高度に最適化されるでしょうか?

これは、問題のオブジェクトを 2 回使用するためのものであることに注意してください。

4

4 に答える 4

2

最初の解決策は、全体的に優れています。

  • vectorelementAtメソッドの呼び出しは 1 回だけです。これは、実際にはここで最もコストのかかる操作であるため、1 回だけ実行するだけで、適切なパフォーマンスが得られます。また、2 回実行すると、いくつかの競合状態が発生する可能性があります。
  • 1 回のキャスト操作のみ。キャストは最新の JVM では非常に安価ですが、それでもわずかなコストがかかります。
  • それはより読みやすいIMHOです。オブジェクトを取得してから、それを使用して 2 つのことを行います。2 回取得した場合、読者は同じオブジェクトを取得していることを頭の中で理解する必要があります。一度取得して、適切な名前の変数に割り当てることをお勧めします。
  • ローカル変数の 1 つの割り当て(最初ptrのソリューションのように) は非常に安価で、多くの場合無料です。Java JIT コンパイラは、ここで高度に最適化されたコードを生成するのに十分スマートです。

PSVectorはかなり古いです。への変換を検討してくださいArrayList<AutoEvent>。ジェネリック ArrayList を使用することで、明示的にキャストする必要がなくなり、a よりもはるかに高速になりますVector(同期されないため、ロックのオーバーヘッドが少ないため)。

于 2013-02-12T04:33:51.027 に答える
0

最初にいくつかの用語をまっすぐに理解しましょう。コードは「新しいオブジェクト参照を作成」しません。から既存のオブジェクト参照を(1回または2回)フェッチしていVectorます。


あなたの質問に答えるために、一度フェッチして参照を一時変数に入れる方が(おそらく)少し速くなります。ただし、違いは小さく、ループで何度も実行しない限り、大きな違いはありません。

(またはのelementAtメソッドは安価です。リストがの実装を持つリンクリストである場合、その呼び出しは高額になる可能性があり、1回または2回の呼び出しの違いは重要になる可能性があります...)VectorArrayListO(1)O(N)elementAt

一般的に言えば、アルゴリズムの複雑さについて考える必要がありますが、それを超えると、最適化する場所を示す確かなプロファイリングの証拠が得られるまで、最適化に時間を費やすべきではありません。


ArrayListもっと適切かどうかは言えません。これは、によって提供されるスレッドセーフが必要な場合ですVector

于 2013-02-12T04:39:34.380 に答える
0

ここで「新しいオブジェクト参照を作成する」とはどういう意味かわかりません。次のコードは、シーケンス要素を取得してキャストし、結果の参照をスタックに格納する((AutoEvent)e_autoSequence.elementAt(currentEventIndex))バイトコードに変換される可能性があります。AutoEvenローカル変数ptrと他のローカル変数もスタックに格納されるため、参照を割り当てると、あるスタック スロットから別の近くのスタック スロットに 4 バイトをコピーするだけです。これは非常に高速な操作です。最新の JVM は参照カウントを行わないため、参照の割り当てはおそらくint値の割り当てと同じくらい安価です。

于 2013-02-12T04:17:57.600 に答える
0

最初の解決策はより高速になります。

その理由は、割り当てがメソッド呼び出しよりも高速に機能するためです。2 番目のケースでは、elementAt() メソッドが 2 回呼び出されるため、処理が遅くなり、JVM は elementAt() で正確に何が起こっているのかがわからないため、おそらくこのコードを最適化できません。

また、Vector のメソッドは同期されているため、ロックの取得によりすべてのメソッドの呼び出しがさらに遅くなることも覚えておいてください。

于 2013-02-12T04:06:44.150 に答える