3

如何执行非阻塞的获取/计算查找并避免缓存踩踏。

这是一个不会踩踏,而是阻塞的示例。

public static <KEY, VALUE> Mono<VALUE> lookupAndWrite(
    Map<KEY, Signal<? extends VALUE>> cacheMap, KEY key, Mono<VALUE> mono) {
    return Mono.defer(() -> Mono.just(cacheMap.computeIfAbsent(key, k -> 
        mono.materialize().block())).dematerialize());
}

这是一个不会阻塞但可以踩踏的例子。

public static <KEY, VALUE> MonoCacheBuilderCacheMiss<KEY, VALUE> lookup(
        Function<KEY, Mono<Signal<? extends VALUE>>> reader, KEY key) {
    return otherSupplier -> writer -> Mono.defer(() ->
            reader.apply(key)
                    .switchIfEmpty(otherSupplier.get()
                            .materialize()
                            .flatMap(signal -> writer.apply(key, signal)
                            )
                    )
                    .dematerialize());
}

有没有不会踩踏或阻塞的方法?在自己的调度程序上订阅阻塞调用是否有意义?

4

1 回答 1

3

重新表述您的问题,您希望在允许异步执行计算的同时避免踩踏。理想情况下,这将使用ConcurrentMap<K, Mono<V>>with来完成computeIfAbsent,如果计算失败,它将丢弃条目。

咖啡因通过使用作为值类型AsyncLoadingCache来提供这种类型的行为。CompletableFuture<V>您可以将阻塞功能重写为

public static <KEY, VALUE> Mono<VALUE> lookupAndWrite(
    AsyncLoadingCache<KEY, VALUE> cache, KEY key, Mono<VALUE> mono) {
  return Mono.defer(() -> Mono.fromFuture(cache.get(key, (k,e) ->
            mono.subscribeOn(Schedulers.fromExecutor(e)).toFuture())));
}

从 2.6.x 版本开始,如果需要,没有更简单AsyncCache的反馈,它将在 2.7 版本中。这还将包括一个ConcurrentMap<K, CompletableFuture<V>>视图,它可以让您概括您的方法以不具有特定于提供程序的接口。目前,您可以通过避免加载方法并使用Caffeine.newBuilder().buildAsync(key -> null).

于 2018-08-14T18:54:36.933 回答