3

アプリケーションで速度に敏感な計算をたくさん行っているので、オートボクシングとパフォーマンスに興味があったので、少しテストを実行しました...

public static void main(String[] args) {
    // Some initialization so I know it's not involved
    ArrayList<Integer> list = new ArrayList<Integer>();
    list.add(0);
    int[] regArray = new int[1];
    long total = 0;

    // This one uses an array and primitive type
    long start = System.currentTimeMillis();
    for (int i = 0; i < 10000000; i++) {
        regArray[0] = i + 10;
        if (regArray[0] % 1000 == 0) total += regArray[0];
    }
    System.out.println("Runtime in millis: " + (System.currentTimeMillis() - start));
    System.out.println(total);

    // This one autoboxes, but still uses the Object type because it's a list
    total = 0;
    start = System.currentTimeMillis();
    for (int i = 0; i < 10000000; i++) {
        list.set(0, i + 10);
        if (list.get(0) % 1000 == 0) total += list.get(0);
    }
    System.out.println("Runtime in millis: " + (System.currentTimeMillis() - start));
    System.out.println(total);

    // This one doesn't autobox
    total = 0;
    start = System.currentTimeMillis();
    for (int i = 0; i < 10000000; i++) {
        list.set(0, new Integer(i + 10));
        if (list.get(0).intValue() % 1000 == 0) total += list.get(0).intValue();
    }
    System.out.println("Runtime in millis: " + (System.currentTimeMillis() - start));
    System.out.println(total);
}

出力例は次のとおりです。

Runtime in millis: 78
50005000000
Runtime in millis: 250
50005000000
Runtime in millis: 250
50005000000

List<>これは、速度に敏感なマシーなアプリケーションから離れてサブクラスを作成する必要があることを示唆しているようです。同意しますか、stackoverflow?

編集:私の実際のユースケースは、頻繁に、そしてほとんど予測できないほど変化する数百int秒を保存する必要があるというfloatことです(私はそれらが狭い範囲内にとどまるために主に言いますが、それらがその中で何をするかわかりません狭い範囲)、これらの数値を計算するには、ミリ秒単位の応答時間が必要です。

4

3 に答える 3

3

マイクロベンチマークは難しいです!キャリパーを使用するようにベンチマークを書き直しました:

import com.google.caliper.Runner;
import com.google.caliper.SimpleBenchmark;

import java.util.ArrayList;

public class ListsBenchmark extends SimpleBenchmark {

    private final ArrayList<Integer> list = new ArrayList<Integer>();
    int[] regArray = new int[1];
    long total;

    @Override
    protected void setUp() throws Exception {
        list.add(0);
        total = 0;
    }

    public long timeArrayAndPrimitiveType(int reps) {
        for (int i = 0; i < reps; i++) {
            regArray[0] = i + 10;
            if (regArray[0] % 1000 == 0)
                total += regArray[0];
        }
        return total;
    }

    public long timeListWithAutoboxing(int reps) {
        for (int i = 0; i < reps; i++) {
            list.set(0, i + 10);
            if (list.get(0) % 1000 == 0)
                total += list.get(0);
        }
        return total;
    }

    public long timeNoAutoboxing(int reps) {
        for (int i = 0; i < reps; i++) {
            list.set(0, new Integer(i + 10));
            if (list.get(0).intValue() % 1000 == 0)
                total += list.get(0).intValue();
        }
        return total;
    }

    public static void main(String[] args) {
        Runner.main(ListsBenchmark.class, new String[]{});
    }

}

元のコードは変更していません。私が見つけたのは:

  • アレイは約3倍高速です
  • 新しいものを作成するInteger方が少し速いです(!)、おそらくキャッシングにはいくらかの価格があるか、それは私のアーキテクチャだけかもしれません(4コアと3 GiBのメモリラップトップを備えた32ビットUbuntu)

チャート上(自分で実行してください!):

キャリパー

于 2012-11-19T21:55:17.083 に答える
2

あらかじめ決められた数のintがある場合、それらを配列に格納することは(格納する必要があり、ストリーミングできないと仮定して!)、一般的にはjava.util.ArrayList、はいよりも高速です。

ただし、多くの場合、データサイズが変化する可能性があるため、動的にサイズ変更可能なコレクションが非常に便利になります。代わりに、通常、独自の実装を作成することもできますArrayList

幸い、オブジェクト(整数など)ではなくプリミティブ型(整数など)に基づいてリストを実装するサードパーティのライブラリが多数あります。あなたはこれらを見ることができます。

于 2012-11-19T21:48:14.320 に答える
1

ベンチマークを作成するのは難しい作業であり、少なくとも次の理由から、ベンチマークは適切ではありません。

  • Hotspotを使用せずに、mainメソッドですべてを実行し、JITがコードをコンパイルすると、結果が正しくなくなります。
  • new Integer()の代わりに使用Integer.valueOf()すると、整数キャッシュを使用できなくなります
  • 値と操作は現実的ではありません。ほとんどの場合、値は0に近く、10,000,000の範囲ではありません

プリミティブと配列は一般にオブジェクトやコレクションよりも高速ですが、実際のコードを測定しないと、現実的な条件下では、プリミティブと配列を使用することで得られる利益が重要であるか、完全に無視できるかを判断するのは困難です。ほとんどの場合、IO操作ではパフォーマンスが低下します。

于 2012-11-19T21:39:01.997 に答える