Complex 数学ライブラリが必要だったので、不変の Complex を使用するライブラリと、可変の Complex を使用するライブラリの間で迷っていました。明らかに、私は計算を適度に高速に実行したいと考えています (読みやすさなどを損なわない限り)。
そこで、可変速度と不変速度の簡単なテストを作成しました。
final class MutableInt {
private int value;
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public MutableInt() {
this(0);
}
public MutableInt(int value) {
this.value = value;
}
}
final class ImmutableInt {
private final int value;
public ImmutableInt(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
public class TestImmutableSpeed {
static long testMutable(final int arrLen) {
MutableInt[] arrMutable = new MutableInt[arrLen];
for (int i = 0; i < arrMutable.length; ++i) {
arrMutable[i] = new MutableInt(i);
for (int j = 0; j < arrMutable.length; ++j) {
arrMutable[i].setValue(arrMutable[i].getValue() + j);
}
}
long sumMutable = 0;
for (MutableInt item : arrMutable) {
sumMutable += item.getValue();
}
return sumMutable;
}
static long testImmutable(final int arrLen) {
ImmutableInt[] arrImmutable = new ImmutableInt[arrLen];
for (int i = 0; i < arrImmutable.length; ++i) {
arrImmutable[i] = new ImmutableInt(i);
for (int j = 0; j < arrImmutable.length; ++j) {
arrImmutable[i] = new ImmutableInt(arrImmutable[i].getValue() + j);
}
}
long sumImmutable = 0;
for (ImmutableInt item : arrImmutable) {
sumImmutable += item.getValue();
}
return sumImmutable;
}
public static void main(String[] args) {
final int arrLen = 1<<14;
long tmStart = System.nanoTime();
System.out.println("sum = " + testMutable(arrLen));
long tmMid = System.nanoTime();
System.out.println("sum = " + testImmutable(arrLen));
long tmEnd = System.nanoTime();
System.out.println("speed comparison mutable vs immutable:");
System.out.println("mutable " + (tmMid - tmStart)/1000000 + " ms");
System.out.println("immutable " + (tmEnd - tmMid)/1000000 + " ms");
}
}
テストの実行が遅すぎる/速すぎる場合は、配列のサイズを調整できます。
-server -Xms256m -XX:+AggressiveOpts で実行すると、次のようになります。
合計 = 2199023247360 合計 = 2199023247360 可変と不変の速度比較: 可変 102 ミリ秒 不変 1506 ミリ秒
質問: いくつかの最適化パラメーターが欠落していますか、それとも不変バージョンは 15 倍遅くなりますか?
もしそうなら、なぜ誰かが不変のクラス Complex を含む数学ライブラリを書くのでしょうか? 不変は「空想」だけで役に立たないのですか?
不変クラスはハッシュマップキーとして安全であるか、競合状態を持たないことを知っていますが、それはどこでも不変性なしで処理できる特殊なケースです。
編集: 1つの回答で示唆されているように、このマイクロベンチマークをキャリパーで再実行しましたが、15倍ではなく12倍遅く、同じポイントで実行されます。Caliper ベンチマーク用に変更されたコード:
com.google.caliper.Runner をインポートします。 com.google.caliper.SimpleBenchmark をインポートします。 最終クラス MutableInt { プライベート int 値; public int getValue() { 戻り値; } public void setValue(int 値) { this.value = 値; } public MutableInt() { これ(0); } public MutableInt(int 値) { this.value = 値; } } 最終クラス ImmutableInt { プライベートの最終的な int 値。 public ImmutableInt(int 値) { this.value = 値; } public int getValue() { 戻り値; } } public class TestImmutableSpeed extends SimpleBenchmark { static long testMutable(final int arrLen) { MutableInt[] arrMutable = new MutableInt[arrLen]; for (int i = 0; i
キャリパーの出力:
0% シナリオ{vm=java、トライアル=0、ベンチマーク=可変、タイプ=-サーバー、minMemory=-Xms256m、最適化=-XX:+AggressiveOpts} 91614044.60 ns; ?=250338.20 ns @ 3 回の試行 50% シナリオ{vm=java、トライアル=0、ベンチマーク=不変、タイプ=-サーバー、minMemory=-Xms256m、最適化=-XX:+AggressiveOpts} 1108057922.00 ns; ?=3920760.98 ns @ 3 回の試行 ベンチマーク ミリ秒線形ランタイム ミュータブル 91.6 == 不変 1108.1 ==============================
Caliper の JVM 出力の最適化パラメータがないことに注意してください。
0% シナリオ{vm=java、トライアル=0、ベンチマーク=可変} 516562214.00 ns; ?=623120.57 ns @ 3 回の試行 50% シナリオ{vm=java、トライアル=0、ベンチマーク=不変} 1706758503.00 ns; ?=5842389.60 ns @ 3 回の試行 ベンチマーク ミリ秒線形ランタイム 可変517 ========= 不変 1707 ==============================
そのため、パラメーターが悪いと両方のバージョンが遅くなりますが、比率はそれほどひどいものではありません (ただし、重要ではありません)。