Javaのプリミティブリストのパフォーマンス比較

1. 概要

このチュートリアルでは、Javaで一般的なlink:/java-list-primitive-int [プリミティブリストライブラリ]のパフォーマンスを比較します*。
そのために、各ライブラリの_add()、get()、_および_contains()_メソッドをテストします。

2. 性能比較

さて、どのライブラリが高速で動作するプリミティブコレクションAPI *を提供しているかを調べましょう。
そのために、_Trove、Fastutil_、および_Colt_の_https://www.baeldung.com/java-arraylist [List] _類似物を比較してみましょう。 パフォーマンステストを作成するには、link:/java-microbenchmark-harness[JMH](Java Microbenchmark Harness)ツールを使用します。

* 2.1。 JMHパラメーター*

次のパラメーターを使用してベンチマークテストを実行します。
@BenchmarkMode(Mode.SingleShotTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@Measurement(batchSize = 100000, iterations = 10)
@Warmup(batchSize = 100000, iterations = 10)
@State(Scope.Thread)
public class PrimitivesListPerformance {
}
ここでは、*各ベンチマークメソッドの実行時間を測定したい*。また、ミリ秒単位で結果を表示したい。
_ @ State_アノテーションは、クラスで宣言された変数がベンチマークテストの実行の一部ではないことを示します。 ただし、これらはベンチマーク手法で使用できます。
さらに、プリミティブのリストを定義しましょう。
public static class PrimitivesListPerformance {
    private List<Integer> arrayList = new ArrayList<>();
    private TIntArrayList tList = new TIntArrayList();
    private cern.colt.list.IntArrayList coltList = new cern.colt.list.IntArrayList();
    private IntArrayList fastUtilList = new IntArrayList();

    private int getValue = 10;
}
これで、ベンチマークを作成する準備が整いました。

3. 追加()

まず、要素をプリミティブリストに追加してテストしましょう。 また、コントロールとして___ArrayList ___を追加します。

* 3.1。 ベンチマークテスト*

最初のマイクロベンチマークは、__https://www.baeldung.com/java-arraylist [ArrayList]â_〜__s _add()_メソッド用です。
@Benchmark
public boolean addArrayList() {
    return arrayList.add(getValue);
}
同様に、Troveの_TIntArrayList.add()_の場合:
@Benchmark
public boolean addTroveIntList() {
    return tList.add(getValue);
}
同様に、Coltの__IntArrayList.add()__は次のようになります。
@Benchmark
public void addColtIntList() {
    coltList.add(getValue);
}
また、Fastutilライブラリの場合、_IntArrayList.add()_メソッドのベンチマークは次のようになります。
@Benchmark
public boolean addFastUtilIntList() {
    return fastUtilList.add(getValue);
}

* 3.2。 試験結果*

次に、実行して結果を比較します。
Benchmark           Mode  Cnt  Score   Error  Units
addArrayList          ss   10  4.527 ± 4.866  ms/op
addColtIntList        ss   10  1.823 ± 4.360  ms/op
addFastUtilIntList    ss   10  2.097 ± 2.329  ms/op
addTroveIntList       ss   10  3.069 ± 4.026  ms/op
結果から、_ArrayListのadd()_が最も遅いオプションであることが明確にわかります。
これは論理的です。* https://www.baeldung.com/java-list-primitive-int [primitive list libraries] *の記事で説明したように、_ArrayList_はboxing / autoboxingを使用してコレクション内にint値を格納します。 したがって、ここで大幅な減速があります。
一方、ColtとFastutilの_add()_メソッドは最速でした。
内部では、3つのライブラリすべてがan _int [] _内に値を格納します。 では、なぜ_add()_メソッドの実行時間が異なるのでしょうか?
答えは、デフォルトの容量がいっぱいのときに_int [] _をどのように増やすかです。
  • * Coltは、内部_int [] _がいっぱいになったときにのみ成長します*

  • 対照的に、* TroveとFastutilはいくつかの追加を使用します
    計算* _int [] _コンテナを展開中

    それが、テスト結果でコルトが勝っている理由です。

4. 取得する()

それでは、_get()_操作マイクロベンチマークを追加しましょう。

* 4.1。 ベンチマークテスト*

まず、__ArrayList '__ s_ get()_操作の場合:
@Benchmark
public int getArrayList() {
    return arrayList.get(getValue);
}
同様に、Troveの__TIntArrayList ___には次のものがあります。
@Benchmark
public int getTroveIntList() {
    return tList.get(getValue);
}
そして、Coltの__cern.colt.list.IntArrayListの場合、___ get()_メソッドは次のようになります。
@Benchmark
public int getColtIntList() {
    return coltList.get(getValue);
}
最後に、Fastutilの_IntArrayList_について、_getInt()_操作をテストします。
@Benchmark
public int getFastUtilIntList() {
    return fastUtilList.getInt(getValue);
}

* 4.2。 試験結果*

その後、ベンチマークを実行して結果を確認します。
Benchmark           Mode  Cnt  Score   Error  Units
getArrayList        ss     20  5.539 ± 0.552  ms/op
getColtIntList      ss     20  4.598 ± 0.825  ms/op
getFastUtilIntList  ss     20  4.585 ± 0.489  ms/op
getTroveIntList     ss     20  4.715 ± 0.751  ms/op
スコアの差はそれほど大きくありませんが、_getArrayList()_の動作が遅いことがわかります。
残りのライブラリについては、ほぼ同じ_get()_メソッド実装があります。 *追加の作業をせずに、_int [] _からすぐに値を取得します*。そのため、Colt、Fastutil、およびTroveが_get()_操作に対して同様のパフォーマンスを発揮します。

*5. contains() *

最後に、リストのタイプごとに_contains()_メソッドをテストしましょう。

* 5.1。 ベンチマークテスト*

__ArrayList '__ s_ contains()_メソッドの最初のマイクロベンチマークを追加しましょう:
@Benchmark
public boolean containsArrayList() {
    return arrayList.contains(getValue);
}
同様に、Troveの__TIntArrayList ___ contains()_ベンチマークは次のようになります。
@Benchmark
public boolean containsTroveIntList() {
    return tList.contains(getValue);
}
同様に、Coltのcer_cern.colt.list.IntArrayList.contains()_のテストは次のとおりです。
@Benchmark
public boolean containsColtIntList() {
    return coltList.contains(getValue);
}
また、Fastutilの__IntArrayListの場合、__the contains()メソッドテストは次のようになります。
@Benchmark
public boolean containsFastUtilIntList() {
    return fastUtilList.contains(getValue);
}

* 5.2。 試験結果*

最後に、テストを実行して結果を比較します。
Benchmark                  Mode  Cnt   Score    Error  Units
containsArrayList          ss     20   2.083  ± 1.585  ms/op
containsColtIntList        ss     20   1.623  ± 0.960  ms/op
containsFastUtilIntList    ss     20   1.406  ± 0.400  ms/op
containsTroveIntList       ss     20   1.512  ± 0.307  ms/op
*通常どおり、_containsArrayList_メソッドのパフォーマンスは最低です*。 対照的に、Trove、Colt、およびFastutilのパフォーマンスは、Javaのコアソリューションに比べて優れています。
今回は、どのライブラリを選択するかは開発者次第です。 3つのライブラリすべての結果は、それらを同一と見なすのに十分近いです。

6. 結論

この記事では、JVMベンチマークテストを通じて、プリミティブリストの実際の実行時パフォーマンスを調査しました。 さらに、テスト結果をJDKの_ArrayList_と比較しました。
また、ここで示す数値はJMHベンチマークの結果にすぎないことに注意してください。*常に特定のシステムとランタイムの範囲でテストします。
いつものように、この記事の完全なコードはhttps://github.com/eugenp/tutorials/tree/master/core-java-modules/core-java-collections-list-3 [GitHub]にあります。