假设我想在 DownloadQueue 中使用缓存像例子。
协程的乐趣在于可以在单线程算法中使用简单的数据结构(例如 HashMap
)。
但是我想使用有限的缓存,并将额外的条目驱逐到较慢的持久存储中。
例如,我可以取 Guava
+ CacheBuilder
+ RemovalListener
: https://github.com/google/guava/wiki/CachesExplained#removal-listeners
这里有一个问题:RemovalListener
是一个非挂起的回调,所以无法将数据推送到 Channels
或来自回调的任何内容。
// This is placed in a suspend context (e.g. within `actor`)
val cache = CacheBuilder.newBuilder().maximumSize(1000)
.expireAfterWrite(10, TimeUnit.SECONDS)
.removalListener<Key, Value> { n ->
expireChannel.sendBlocking(n.value!!) // <-- could sendBlocking be used here???
}.build<Key, Value>()
据我了解,
runBlocking
阻塞当前线程的执行,因此它阻塞当前协程,并且它将无法接收/处理数据。有没有办法制作
RemovalListener
-like 回调协程友好?我可以想象使用由
RemovalListener
填充的无界队列的解决方法。而有问题的协程最终会检查队列。
最佳答案
不阻塞删除监听器(从而破坏缓存)的唯一方法是拥有一个缓冲 channel 。这意味着两个变化:
SendChannel
具有非零容量,请参阅 Channel(capacity)
考虑不同的行为。这主要取决于如果超过消费者可以处理的元素过期,应该采取什么行为。 SendChannel.offer()
而不是 SendChannel.sendBlocking()
.如果返回 false
您可以实现备份行为,例如记录故障,以便找出内存和丢失事件之间的最佳平衡点。 关于kotlin - 将数据从回调推送到 Kotlin 协程的方法是什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53263690/