我正在使用HashMap在单线程环境中构造一个频率映射。键是弦,它的频率需要跟踪。
如果我使用HashMap,则每个增量都需要一个新的整数。
对于这个用例,LongAdder会表现得更好吗,因为我可以简单地调用can ()吗?一些基本的测试表明,LongAdder确实表现得稍微好一些,但我不知道为什么。
发布于 2021-01-27 23:09:24
测试以确定增量积分类型的相对性能。
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.LongAdder;
import java.util.function.Function;
public class LongAdderTest {
public static void main(String[] args) {
new LongAdderTest().start();
}
public void start() {
int N = 100_000_000;
int warmup = 3;
String[] testNames = { "LongAdder", "Long", "Integer", "long",
"int", "Object", "int[]", "long[]" };
List<Function<Integer, Long>> tests = List.of(
this::longAdderTest, this::longWrapperTest,
this::integerWrapperTest, this::primitiveLongTest,
this::primitiveIntTest, this::objectTest,
this::intArrayTest, this::longArrayTest);
int i = 0;
for (Function<Integer, Long> test : tests) {
runTest(test, warmup, N, testNames[i++]);
}
}
public void runTest(Function<Integer, Long> test, int warmup,
int iterations, String testName) {
// warmup cycle
for (int i = 0; i < warmup; i++) {
long v = test.apply(iterations);
if (v != iterations) {
System.out
.println("Unexpected result - return = " + v);
}
}
long start = System.nanoTime();
long val = test.apply(iterations);
System.out.printf("%-10s : %12f %d%n", testName,
(System.nanoTime() - start) / 1_000_000., val);
}
public long longAdderTest(int iter) {
LongAdder val = new LongAdder();
Map<String, LongAdder> freq = new HashMap<>();
freq.put("A", val);
for (int i = 0; i < iter; i++) {
freq.get("A").increment();
}
return freq.get("A").longValue();
}
public long longWrapperTest(int iter) {
Long val = 0L;
Map<String, Long> freq = new HashMap<>();
freq.put("A", val);
for (int i = 0; i < iter; i++) {
freq.computeIfPresent("A", (k, v) -> v + 1);
}
return freq.get("A");
}
public long integerWrapperTest(int iter) {
Integer val = 0;
Map<String, Integer> freq = new HashMap<>();
freq.put("A", val);
for (int i = 0; i < iter; i++) {
freq.computeIfPresent("A", (k, v) -> v + 1);
}
return freq.get("A");
}
public long primitiveLongTest(int iter) {
Map<String, Long> freq = new HashMap<>();
long val = 0;
freq.put("A", val);
for (int i = 0; i < iter; i++) {
freq.computeIfPresent("A", (k, v) -> v + 1);
}
return freq.get("A");
}
public long primitiveIntTest(int iter) {
Map<String, Integer> freq = new HashMap<>();
int val = 0;
freq.put("A", val);
for (int i = 0; i < iter; i++) {
freq.computeIfPresent("A", (k, v) -> v + 1);
}
return freq.get("A");
}
public long intArrayTest(int iter) {
Map<String, int[]> freq = new HashMap<>();
int[] val = { 0 };
freq.put("A", val);
for (int i = 0; i < iter; i++) {
freq.get("A")[0] += 1;
}
return freq.get("A")[0];
}
public long longArrayTest(int iter) {
Map<String, long[]> freq = new HashMap<>();
long[] val = { 0L };
freq.put("A", val);
for (int i = 0; i < iter; i++) {
freq.get("A")[0] += 1;
}
return freq.get("A")[0];
}
public long objectTest(int iter) {
MyLongIncrement longObject = new MyLongIncrement(0);
Map<String, MyLongIncrement> freq = new HashMap<>();
freq.put("A", longObject);
for (int i = 0; i < iter; i++) {
freq.get("A").increment();
}
return freq.get("A").get();
}
static class MyLongIncrement {
long val;
public MyLongIncrement(long v) {
this.val = v;
}
public long get() {
return val;
}
public void increment() {
val += 1l;
}
}
}试运行。
LongAdder : 4166.724472 100000000
Long : 2929.021352 100000000
Integer : 5487.358323 100000000
long : 2993.538570 100000000
int : 2505.171838 100000000
Object : 1032.322116 100000000
int[] : 1132.710126 100000000
long[] : 1107.633331 100000000详细信息
使用Map的
LongAdder来说也是一样,但是同步代码可能是一个因素(或者测试设计器),因为它的性能不那么出色。但是,可能有许多因素,包括我访问map值的方法.我想我受够了。希望它能对这个问题有所启发。
https://stackoverflow.com/questions/65927505
复制相似问题