我需要一些复杂的数学库,因此我在使用不可变复合体的库和使用可变复合体的库之间犹豫了一下。显然,我希望计算能够以相当快的速度运行(除非它破坏了可读性等)。
因此,我创建了速度可变与不可变的简单测试:
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 速度比较可变与不可变:可变102 ms 不变1506 ms
问题:我是否缺少一些优化参数,或者不可变版本的速度慢15倍?
如果是这样,为什么有人会在其中编写不可变类Complex的数学库呢?不变的东西只是“花哨”而没有用吗?
我知道不可变类作为哈希映射键比较安全,也不能具有竞争条件,但是在特殊情况下,无处不在都可以进行不可变性处理。
编辑:我按照一个答案的建议,用卡尺重新运行了这个微基准测试,它的运行速度慢了12倍,而不是15倍,仍然是同一点。更改了Caliper基准测试的代码:
导入com.google.caliper.Runner; 导入com.google.caliper.SimpleBenchmark; 最后一个类MutableInt { private int value; public int getValue(){ 返回值; } public void setValue(int value){ this.value = value; } public MutableInt(){ this(0); } public MutableInt(int value){ this.value = value; } } final class ImmutableInt { 私人final int值; public ImmutableInt(int value){ this.value = value; } public int getValue(){ 返回值; } } 公共类TestImmutableSpeed扩展SimpleBenchmark { 静态长testMutable(final int arrLen){ MutableInt [] arrMutable = new MutableInt [arrLen]; 为(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 ======================== ====
因此,错误的参数会使两个版本都变慢,但是比率却不太可怕(但仍然不重要)。
不变性有时会带来速度损失。如果速度很重要,则将数学库与可变的Complex一起使用。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句