gpt4 book ai didi

java不可变类慢得多

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:55:47 24 4
gpt4 key购买 nike

我需要一些 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我得到:

sum = 2199023247360sum = 2199023247360speed comparison mutable vs immutable:mutable   102 msimmutable 1506 ms

问题:我是否遗漏了一些优化参数,或者不可变版本是否慢了 15 倍?

如果是,为什么会有人编写其中包含不可变类 Complex 的数学库?不可变只是“花哨”但没用吗?

我知道不可变类作为 HashMap 键更安全,或者不能有竞争条件,但这是特殊情况,可以在没有不可变性的情况下处理。

编辑:按照一个答案的建议,我用卡尺重新运行了这个微基准测试,它运行速度慢了 12 倍,而不是 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 trials50% Scenario{vm=java, trial=0, benchmark=Immutable, type=-server, minMemory=-Xms256m, optimizations=-XX:+AggressiveOpts} 1108057922.00 ns; ?=3920760.98 ns @ 3 trialsbenchmark     ms linear runtime  Mutable   91.6 ==Immutable 1108.1 ==============================

请注意,在没有优化参数的情况下,Caliper 的 JVM 输出是:

 0% Scenario{vm=java, trial=0, benchmark=Mutable} 516562214.00 ns; ?=623120.57 ns @ 3 trials50% Scenario{vm=java, trial=0, benchmark=Immutable} 1706758503.00 ns; ?=5842389.60 ns @ 3 trialsbenchmark   ms linear runtime  Mutable  517 =========Immutable 1707 ==============================

如此糟糕的参数使两个版本都变慢,但比率没那么糟糕(但不重要,仍然)。

最佳答案

这很有趣。好吧,首先,这不是一个公平的测试;当你这样做时,你并没有预热 JVM。基准测试通常很难进行。我重构了您的代码以使用 Google Caliper ,得到了相似但不同的结果;不可变类只慢了 3 倍。还不确定为什么。无论如何,这是到目前为止的工作:

TestImmutableSpeed.java

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

public class TestImmutableSpeed {
static 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;
}
}

static final class ImmutableInt {
private final int value;

public ImmutableInt(int value) {
this.value = value;
}

public int getValue() {
return value;
}
}

public static class TestBenchmark extends SimpleBenchmark {
public void timeMutable(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();
}
System.out.println(sumMutable);
}

public void timeImmutable(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();
}
System.out.println(sumImmutable);
}
}

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

卡尺输出

 0% Scenario{vm=java, trial=0, benchmark=Immutable} 78574.05 ns; σ=21336.61 ns @ 10 trials
50% Scenario{vm=java, trial=0, benchmark=Mutable} 24956.94 ns; σ=7267.78 ns @ 10 trials

benchmark us linear runtime
Immutable 78.6 ==============================
Mutable 25.0 =========

vm: java
trial: 0

字符串更新

所以我考虑得更多,决定尝试将包装类从 int 更改为对象,在本例中为 String。将静态类更改为 String,并使用 Integer.valueOf(i).toString() 加载字符串,而不是将它们添加到 中StringBuilder,我得到了这些结果:

 0% Scenario{vm=java, trial=0, benchmark=Immutable} 11034616.91 ns; σ=7006742.43 ns @ 10 trials
50% Scenario{vm=java, trial=0, benchmark=Mutable} 9494963.68 ns; σ=6201410.87 ns @ 10 trials

benchmark ms linear runtime
Immutable 11.03 ==============================
Mutable 9.49 =========================

vm: java
trial: 0

但是,我认为在这种情况下,差异主要在于必须发生的所有数组复制,而不是它使用 String 的事实。

关于java不可变类慢得多,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16317349/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com