6

私は Molecular Dynamic アルゴリズムをテストしていました。これは、とりわけ、9 つの double 配列で構成されたクラス Particle を持ち、粒子コンポーネント (3D 環境での速度、力、および位置) を格納します。

5 つの入力サイズを使用してアルゴリズムをテストします。

Size (MB) Time (s)
0.06      0.36     (fits in cache L2)
0.14      1.79     (fits in cache L2)
0.60      36.86    (fits in cache L3)
1.35      182.24   (fits in cache L3)
17.38     566.55   (it only fits in RAM)

Particlesレイアウトを からarrayに変更しますArrayList。連続したメモリ ブロックを作成するために、占有するサイズで arrayList を作成しました。

ArrayList <Double> px = new ArrayList <Double>(Input_Size);

上記の睾丸と同じ条件でバージョンを実行したところ、結果は次のようになりました。

Size (MB) Time (s)
0.06      0.608
0.14      2.78
0.60      57.15
1.35      299.24
17.38     1436,42

テスト環境は次のとおりです。

AMD Opteron プロセッサ 6174、800 MHz、12 MB キャッシュ L3、24 コア。

約2倍のスピードダウンを得ています。これは正常ですか?ArrayList配列のようにメモリに連続して割り当てられるため、両方のバージョンでほぼ同じ時間を期待するべきではありませんか?

編集:

Running with the option **-XX:+PrintCompilation**

  WITH ARRAY:

 1       java.util.jar.Manifest$FastInputStream::readLine (167 bytes)
  2       sun.nio.cs.UTF_8$Decoder::decodeArrayLoop (553 bytes)
  3       java.lang.String::hashCode (60 bytes)
  4       java.lang.String::charAt (33 bytes)
  5       sun.security.util.ManifestDigester::findSection (180 bytes)
  6       java.lang.Object::<init> (1 bytes)
  7       moldyn.random::update (104 bytes)
  8       moldyn.random::seed (80 bytes)
---   n   java.lang.StrictMath::log (static)
  9       java.lang.Math::log (5 bytes)
 10       moldyn.md::scalingVelocity (82 bytes)
 11       moldyn.Particles::distance (192 bytes)
  1%      moldyn.Particles::force @ 42 (211 bytes)
 12       moldyn.Particles::force (211 bytes)
 13       moldyn.Particles::domove (163 bytes)
 14       moldyn.Particles::domove_out (160 bytes)
  2%      moldyn.Particles::cicle_domove @ 5 (23 bytes)
 15       moldyn.Particles::update_force (49 bytes)
  3%      moldyn.Particles::cicle_forces @ 6 (27 bytes)
 16       moldyn.Particles::mkekin (141 bytes)
  4%      moldyn.Particles::cicle_mkekin @ 9 (33 bytes)
 17       moldyn.Particles::velavg (70 bytes)
  5%      moldyn.Particles::cicle_velavg @ 9 (37 bytes)
 18       moldyn.Particles::cicle_domove (23 bytes)
 19       moldyn.Particles::cicle_forces (27 bytes)
 20       moldyn.Particles::cicle_mkekin (33 bytes)
 21       moldyn.Particles::cicle_velavg (37 bytes)
36.763

WITH ArrayList <Double>....
----

  1       java.util.jar.Manifest$FastInputStream::readLine (167 bytes)
  2       sun.nio.cs.UTF_8$Decoder::decodeArrayLoop (553 bytes)
  3       java.lang.String::hashCode (60 bytes)
  4       java.lang.String::charAt (33 bytes)
  5       sun.security.util.ManifestDigester::findSection (180 bytes)
  6       java.lang.Object::<init> (1 bytes)
---   n   java.lang.System::arraycopy (static)
  7       java.lang.Number::<init> (5 bytes)
  8       java.util.ArrayList::ensureCapacity (58 bytes)
  9       java.lang.Double::valueOf (9 bytes)
 10       java.lang.Double::<init> (10 bytes)
 11       java.util.ArrayList::add (100 bytes)
 12       java.util.ArrayList::RangeCheck (48 bytes)
 13       java.util.ArrayList::set (21 bytes)
 14       moldyn.random::update (104 bytes)
 15       moldyn.random::seed (80 bytes)
---   n   java.lang.StrictMath::log (static)
 16       java.lang.Math::log (5 bytes)
 17       java.util.ArrayList::get (12 bytes)
 18       java.lang.Double::doubleValue (5 bytes)
 19       moldyn.md::scalingVelocity (120 bytes)
 20       moldyn.Particles::distance (240 bytes)
  1%      moldyn.Particles::force @ 42 (211 bytes)
 21       moldyn.Particles::force (211 bytes)
 22       moldyn.Particles::domove (337 bytes)
 23       moldyn.Particles::domove_out (292 bytes)
  2%      moldyn.Particles::cicle_domove @ 5 (23 bytes)
 24       moldyn.Particles::update_force (91 bytes)
  3%      moldyn.Particles::cicle_forces @ 6 (27 bytes)
 25       moldyn.Particles::mkekin (297 bytes)
  4%      moldyn.Particles::cicle_mkekin @ 9 (33 bytes)
 26       moldyn.Particles::velavg (118 bytes)
  5%      moldyn.Particles::cicle_velavg @ 9 (37 bytes)
 27       moldyn.Particles::cicle_domove (23 bytes)
 28       moldyn.Particles::cicle_forces (27 bytes)
 29       moldyn.Particles::cicle_mkekin (33 bytes)
 30       moldyn.Particles::cicle_velavg (37 bytes)
55.98
4

3 に答える 3

6

いくつかの考えがありますが、決定的な答えはありません。

  1. Aはプリミティブjava.lang.Doubleと同じではありません。オブジェクトdoubleに伴うオートボクシングのオーバーヘッドと追加の機械が違いを生む可能性があります。Doubleバイトコードを比較して、それが正しいかどうかを確認します。
  2. クラス内のクライアントから隠されているdouble []かの選択のように聞こえます。その場合は、内部実装の詳細であるため、配列を使用してください。List<Double>Particle
  3. ベンチマーク テストでだまされないように注意します。
  4. あなたのParticleクラスが変更可能かどうか疑問に思います。それは違いを生むかもしれません。位置、速度、および力は継続的に変化し、オブジェクトで更新されますか?
于 2012-11-25T18:26:01.900 に答える
2

潜在的な問題が 2 つあります。

1: 配列の周りのオブジェクトのオーバーヘッド...

ArrayList は、可変数のオブジェクトを Array に格納します。これはオブジェクトの配列を作成するのと似ていますが、ArrayList を使用すると、公開されたメソッドを使用して ArrayList に項目を簡単に追加および削除でき、動的にサイズ変更されます。

これは非常に便利ですが、多くの要素を使用する場合、オブジェクトの配列を作成するよりも遅くなります。

ArrayList は、機能が制限された非常に柔軟な Array タイプのコレクションが必要な場合に適しています。しかし、スピードを求めるならアレイが勝つでしょう。ArrayList 内の配列の内部再コピーを避けるために、使用できます

ensureCapacity(int requestCapacity) 

2: また、あなたの特定のケースでは、多くの Boxing/unBoxing が前後に行われている可能性がdoubleありDoubleます。これにより、遅延も発生します。

于 2012-11-25T18:23:36.923 に答える
1

このユース ケースでは、配列または ArrayList を使用しないことをお勧めします。配列を優先して無視されている、これに対する非常に明白なオブジェクト指向のソリューションがあります。

より良い構造化されたプログラムを構築するには、むしろコンポジションを使用する必要があります。これにより、読みやすくなり、(おそらく)追加のオーバーヘッドが発生しなくなります。

例えば。

import javax.vecmath.Vector3d;

public class Particle {

    private Vector3d velocity;
    private Vector3d force; // acceleration?
    private Vector3d position; 

    ...

}

この方法では、(配列と ArrayList の両方の場合のように) 境界チェックについて心配する必要がなく、(ArrayLists の場合のように) 自動ボクシングについて心配する必要もありません。また、粒子の速度、加速度、および位置の各値に適切な名前が付けられるという利点も得られます。つまり、誰が何particle.getData()[7]を参照しているかを知っていますが、それはparticle.getPosition().y非常に明白です。最後に、Vector3d役に立つかもしれないいくつかの組み込み機能が付属しています。

于 2012-11-25T20:06:14.560 に答える