我有一个使用协程的 Kotlin JVM 服务器应用程序,我需要在非阻塞网络调用前面放置一个缓存。我想我可以使用咖啡因AsyncLoadingCache
来获得我需要的非阻塞缓存行为。AsyncCacheLoader
我需要实现的接口使用CompletableFuture
. 同时,我要调用的加载缓存条目的方法是一个suspend
函数。
我可以像这样弥合差距:
abstract class SuspendingCacheLoader<K, V>: AsyncCacheLoader<K, V> {
abstract suspend fun load(key: K): V
final override fun asyncLoad(key: K, executor: Executor): CompletableFuture<V> {
return GlobalScope.async(executor.asCoroutineDispatcher()) {
load(key)
}.asCompletableFuture()
}
}
这将在提供的(默认情况下, the )上运行该load
函数,从 Caffeine 的角度来看,这是正确的行为。Executor
ForkJoinPool
但是,我知道我应该尽量避免使用 GlobalScope 来启动 coroutines。
我考虑让我的SuspendingCacheLoader
实现CoroutineScope
和管理自己的协程上下文。但CoroutineScope
旨在由具有托管生命周期的对象实现。缓存和 都没有AsyncCacheLoader
任何生命周期钩子。缓存拥有Executor
和CompletableFuture
实例,因此它已经以这种方式控制了加载任务的生命周期。我看不出让协程上下文拥有任务会添加任何东西,而且我担心在缓存停止使用后我将无法正确关闭协程上下文。
编写自己的异步缓存机制非常困难,所以如果可以的话,我想与 Caffeine 实现集成。
是使用GlobalScope
正确的方法来实现AsyncCacheLoader
,还是有更好的解决方案?