如何使用 Guava 缓存代替 HashMap?
How to use Guava cache instead of HashMap?
我已经使用 HashMap
来存储斐波那契值。
这是此代码执行的输出:
Enter n: 500000
F(500000) = 2955561408 ... computed in 5,141 ms
Enter n: 500000
F(500000) = 2955561408 ... computed in 0 ms
缓存很好,return结果很好
我想更换更好的Guava cache
,我已经失去了任何利润。
代码执行输出:
Enter n: 500000
F(500000) = 2955561408 ... computed in 5,184 ms
Enter n: 500000
F(500000) = 2955561408 ... computed in 5,086 ms
程序代码如下:
public class CachedFibonacci {
private static Map<BigDecimal, BigDecimal> previousValuesHolder;
static {
previousValuesHolder = new HashMap<>();
previousValuesHolder.put(BigDecimal.ZERO, BigDecimal.ZERO);
previousValuesHolder.put(BigDecimal.ONE, BigDecimal.ONE);
}
private static LoadingCache<BigDecimal, BigDecimal> cachedFibonacci = CacheBuilder.newBuilder()
.expireAfterWrite(3, TimeUnit.MINUTES)
.maximumSize(500000)
.concurrencyLevel(5)
.weakKeys()
.build(new CacheLoader<BigDecimal, BigDecimal>() {
@Override
public BigDecimal load(BigDecimal key) throws Exception {
return getFibonacciByKey(key);
}
});
private static BigDecimal getFibonacciByKey(BigDecimal key) {
long number = key.longValue();
BigDecimal olderValue = BigDecimal.ONE,
oldValue = BigDecimal.ONE,
newValue = BigDecimal.ONE;
for (int i = 3; i <= number; i++) {
newValue = oldValue.add(olderValue);
olderValue = oldValue;
oldValue = newValue;
}
return newValue;
}
public static BigDecimal getGuavaCache(long number) {
if (0 == number) {
return BigDecimal.ZERO;
} else if (1 == number) {
return BigDecimal.ONE;
} else {
return cachedFibonacci.getUnchecked(BigDecimal.valueOf(number));
}
}
public static BigDecimal getCachedFibonacciOf(long number) {
if (0 == number) {
return BigDecimal.ZERO;
} else if (1 == number) {
return BigDecimal.ONE;
} else {
if (previousValuesHolder.containsKey(BigDecimal.valueOf(number))) {
return previousValuesHolder.get(BigDecimal.valueOf(number));
} else {
BigDecimal olderValue = BigDecimal.ONE,
oldValue = BigDecimal.ONE,
newValue = BigDecimal.ONE;
for (int i = 3; i <= number; i++) {
newValue = oldValue.add(olderValue);
olderValue = oldValue;
oldValue = newValue;
}
previousValuesHolder.put(BigDecimal.valueOf(number), newValue);
return newValue;
}
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.print("Enter n: ");
long inputNumber = scanner.nextLong();
if (inputNumber >= 0) {
long beginTime = System.nanoTime();
// BigDecimal fibo = getCachedFibonacciOf(inputNumber);
BigDecimal fibo = getGuavaCache(inputNumber);
long endTime = System.nanoTime();
long delta = endTime - beginTime;
System.out.printf("F(%d) = %.10s ... computed in %,d ms\n", inputNumber, fibo, delta / 1_000_000);
} else {
System.err.println("You must enter number > 0");
System.out.println("try, enter number again, please:");
break;
}
}
}
}
我想当你调用 cachedFibonacci.getUnchecked()
它应该 return 缓存值,如果它被缓存,否则计算它并缓存。
这段代码为什么要用Guava缓存重新计算一次?
如何解决这个问题?
如果删除行
.weakKeys()
从构建缓存,你会看到计算速度加快。
来自 javaDoc
Warning: when this method is used, the resulting cache will use identity ({@code ==})
- comparison to determine equality of keys.
我已经使用 HashMap
来存储斐波那契值。
这是此代码执行的输出:
Enter n: 500000
F(500000) = 2955561408 ... computed in 5,141 ms
Enter n: 500000
F(500000) = 2955561408 ... computed in 0 ms
缓存很好,return结果很好
我想更换更好的Guava cache
,我已经失去了任何利润。
代码执行输出:
Enter n: 500000
F(500000) = 2955561408 ... computed in 5,184 ms
Enter n: 500000
F(500000) = 2955561408 ... computed in 5,086 ms
程序代码如下:
public class CachedFibonacci {
private static Map<BigDecimal, BigDecimal> previousValuesHolder;
static {
previousValuesHolder = new HashMap<>();
previousValuesHolder.put(BigDecimal.ZERO, BigDecimal.ZERO);
previousValuesHolder.put(BigDecimal.ONE, BigDecimal.ONE);
}
private static LoadingCache<BigDecimal, BigDecimal> cachedFibonacci = CacheBuilder.newBuilder()
.expireAfterWrite(3, TimeUnit.MINUTES)
.maximumSize(500000)
.concurrencyLevel(5)
.weakKeys()
.build(new CacheLoader<BigDecimal, BigDecimal>() {
@Override
public BigDecimal load(BigDecimal key) throws Exception {
return getFibonacciByKey(key);
}
});
private static BigDecimal getFibonacciByKey(BigDecimal key) {
long number = key.longValue();
BigDecimal olderValue = BigDecimal.ONE,
oldValue = BigDecimal.ONE,
newValue = BigDecimal.ONE;
for (int i = 3; i <= number; i++) {
newValue = oldValue.add(olderValue);
olderValue = oldValue;
oldValue = newValue;
}
return newValue;
}
public static BigDecimal getGuavaCache(long number) {
if (0 == number) {
return BigDecimal.ZERO;
} else if (1 == number) {
return BigDecimal.ONE;
} else {
return cachedFibonacci.getUnchecked(BigDecimal.valueOf(number));
}
}
public static BigDecimal getCachedFibonacciOf(long number) {
if (0 == number) {
return BigDecimal.ZERO;
} else if (1 == number) {
return BigDecimal.ONE;
} else {
if (previousValuesHolder.containsKey(BigDecimal.valueOf(number))) {
return previousValuesHolder.get(BigDecimal.valueOf(number));
} else {
BigDecimal olderValue = BigDecimal.ONE,
oldValue = BigDecimal.ONE,
newValue = BigDecimal.ONE;
for (int i = 3; i <= number; i++) {
newValue = oldValue.add(olderValue);
olderValue = oldValue;
oldValue = newValue;
}
previousValuesHolder.put(BigDecimal.valueOf(number), newValue);
return newValue;
}
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.print("Enter n: ");
long inputNumber = scanner.nextLong();
if (inputNumber >= 0) {
long beginTime = System.nanoTime();
// BigDecimal fibo = getCachedFibonacciOf(inputNumber);
BigDecimal fibo = getGuavaCache(inputNumber);
long endTime = System.nanoTime();
long delta = endTime - beginTime;
System.out.printf("F(%d) = %.10s ... computed in %,d ms\n", inputNumber, fibo, delta / 1_000_000);
} else {
System.err.println("You must enter number > 0");
System.out.println("try, enter number again, please:");
break;
}
}
}
}
我想当你调用 cachedFibonacci.getUnchecked()
它应该 return 缓存值,如果它被缓存,否则计算它并缓存。
这段代码为什么要用Guava缓存重新计算一次?
如何解决这个问题?
如果删除行
.weakKeys()
从构建缓存,你会看到计算速度加快。
来自 javaDoc
Warning: when this method is used, the resulting cache will use identity ({@code ==})
- comparison to determine equality of keys.