Мне понадобилась какая-то сложная математическая библиотека, поэтому я колебался между библиотеками, которые используют неизменяемый Complex и библиотеки, которые используют mutable Complex. Очевидно, я хочу, чтобы вычисления выполнялись достаточно быстро (если только он не убивает читаемость и т.д.).
Итак, я создал простой тест скорости mutable vs immutable:
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 И я получаю:
sum = 2199023247360 sum = 2199023247360 speed comparison mutable vs immutable: mutable 102 ms immutable 1506 ms
Вопрос: Не хватает ли параметра оптимизации, или является неизменной версией 15x медленнее?
Если это так, зачем кому-нибудь писать математическую библиотеку с неизменяемым классом Complex в ней? Неизменяется просто "причудливо", но бесполезно?
Я знаю, что неизменный класс более безопасен как ключ карты хэша или не может иметь условия гонки, но это особые случаи, которые можно обрабатывать без неизменности везде.
Изменить: Я снова запустил этот микрообъект с помощью суппорта, как это было предложено одним ответом, и он работает на 12x медленнее, а не на 15 раз, по-прежнему остается той же точкой. Изменен код для тестирования Caliper:
import com.google.caliper.Runner; import com.google.caliper.SimpleBenchmark; 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 extends SimpleBenchmark { static long testMutable(final int arrLen) { MutableInt[] arrMutable = new MutableInt[arrLen]; for (int i = 0; i
Выход суппорта:
0% Scenario{vm=java, trial=0, benchmark=Mutable, type=-server, minMemory=-Xms256m, optimizations=-XX:+AggressiveOpts} 91614044.60 ns; ?=250338.20 ns @ 3 trials 50% Scenario{vm=java, trial=0, benchmark=Immutable, type=-server, minMemory=-Xms256m, optimizations=-XX:+AggressiveOpts} 1108057922.00 ns; ?=3920760.98 ns @ 3 trials benchmark ms linear runtime Mutable 91.6 == Immutable 1108.1 ==============================
Обратите внимание, что без параметров оптимизации для выхода JVM для суппорта:
0% Scenario{vm=java, trial=0, benchmark=Mutable} 516562214.00 ns; ?=623120.57 ns @ 3 trials 50% Scenario{vm=java, trial=0, benchmark=Immutable} 1706758503.00 ns; ?=5842389.60 ns @ 3 trials benchmark ms linear runtime Mutable 517 ========= Immutable 1707 ==============================
Такие плохие параметры делают обе версии медленными, но соотношение менее страшное (но не важно, все же).