5个版本
0.10.3 | 2024年1月8日 |
---|---|
0.10.2 | 2023年8月13日 |
0.10.1 | 2023年7月10日 |
0.10.0 | 2022年11月18日 |
0.9.6 | 2022年11月7日 |
#8 在 缓存 类别中
每月下载量 116,231
在 57 个 Crates中(直接使用12个)
245KB
5K SLoC
Mini Moka
Mini Moka 是一个用于Rust的快速、并发缓存库。Mini Moka 是 Moka 的轻量级版本。
Mini Moka 在哈希表之上提供缓存实现。它们支持检索的全并发和更新的高预期并发。Mini Moka 还提供了一个非线程安全的缓存实现,适用于单线程应用程序。
所有缓存都通过使用替换算法来对哈希表进行最佳努力限制,以确定在容量超过时应该驱逐哪些条目。
功能
- 线程安全,内存中高度并发。
- 缓存可以通过以下之一进行限制
- 最大条目数。
- 条目的总加权大小。(大小感知驱逐)
- 通过使用受Caffeine启发的条目替换算法来保持接近最佳命中率
- 通过最少使用(LFU)策略控制缓存访问。
- 通过最近最少使用(LRU)策略控制缓存驱逐。
- 更多详细信息和一些基准测试结果在此处提供.
- 支持过期策略
- 存活时间
- 空闲时间
变更日志
目录
- 功能
- 变更日志
- 使用方法
- 示例:同步缓存
- 避免在
get
时克隆值 - 示例(第二部分)
- 最低支持的Rust版本
- 开发Mini Moka
- 鸣谢
- 许可证
使用方法
将其添加到您的 Cargo.toml
[dependencies]
mini_moka = "0.10"
示例:同步缓存
线程安全、同步缓存在 sync
模块中定义。
通过 insert
方法手动添加缓存条目,并在缓存中存储,直到被驱逐或手动失效。
以下是一个使用多个线程读取和更新缓存的示例
// Use the synchronous cache.
use mini_moka::sync::Cache;
use std::thread;
fn value(n: usize) -> String {
format!("value {}", n)
}
fn main() {
const NUM_THREADS: usize = 16;
const NUM_KEYS_PER_THREAD: usize = 64;
// Create a cache that can store up to 10,000 entries.
let cache = Cache::new(10_000);
// Spawn threads and read and update the cache simultaneously.
let threads: Vec<_> = (0..NUM_THREADS)
.map(|i| {
// To share the same cache across the threads, clone it.
// This is a cheap operation.
let my_cache = cache.clone();
let start = i * NUM_KEYS_PER_THREAD;
let end = (i + 1) * NUM_KEYS_PER_THREAD;
thread::spawn(move || {
// Insert 64 entries. (NUM_KEYS_PER_THREAD = 64)
for key in start..end {
my_cache.insert(key, value(key));
// get() returns Option<String>, a clone of the stored value.
assert_eq!(my_cache.get(&key), Some(value(key)));
}
// Invalidate every 4 element of the inserted entries.
for key in (start..end).step_by(4) {
my_cache.invalidate(&key);
}
})
})
.collect();
// Wait for all threads to complete.
threads.into_iter().for_each(|t| t.join().expect("Failed"));
// Verify the result.
for key in 0..(NUM_THREADS * NUM_KEYS_PER_THREAD) {
if key % 4 == 0 {
assert_eq!(cache.get(&key), None);
} else {
assert_eq!(cache.get(&key), Some(value(key)));
}
}
}
避免在 get
时克隆值
对于并发缓存(sync
缓存),get
方法的返回类型是 Option<V>
,而不是 Option<&V>
,其中 V
是值类型。每次对现有键调用 get
时,都会创建存储的值 V
的一个克隆并返回它。这是因为 Cache
允许线程并发更新,所以存储在缓存中的值可以在任何时候被任何其他线程删除或替换。由于无法保证值超出引用的寿命,get
不能返回引用 &V
。
如果您想存储克隆成本高昂的值,请在将其存储到缓存之前用 std::sync::Arc
包装。Arc
是一个线程安全的引用计数指针,其 clone()
方法成本低。
use std::sync::Arc;
let key = ...
let large_value = vec![0u8; 2 * 1024 * 1024]; // 2 MiB
// When insert, wrap the large_value by Arc.
cache.insert(key.clone(), Arc::new(large_value));
// get() will call Arc::clone() on the stored value, which is cheap.
cache.get(&key);
示例:大小感知驱逐
如果不同的缓存条目有不同的“权重” — 例如,每个条目有不同的内存占用 — 您可以在创建缓存时指定一个 weigher
闭包。闭包应返回一个条目的加权大小(相对大小),单位为 u32
,并且当总加权大小超过其 max_capacity
时,缓存将驱逐条目。
use std::convert::TryInto;
use mini_moka::sync::Cache;
fn main() {
let cache = Cache::builder()
// A weigher closure takes &K and &V and returns a u32 representing the
// relative size of the entry. Here, we use the byte length of the value
// String as the size.
.weigher(|_key, value: &String| -> u32 {
value.len().try_into().unwrap_or(u32::MAX)
})
// This cache will hold up to 32MiB of values.
.max_capacity(32 * 1024 * 1024)
.build();
cache.insert(0, "zero".to_string());
}
请注意,在做出驱逐选择时,不使用加权大小。
示例:过期策略
Mini Moka 支持以下过期策略
- 生存时间:缓存的条目将在从
insert
开始指定的持续时间后过期。 - 空闲时间:缓存的条目将在从
get
或insert
开始指定的持续时间后过期。
要设置它们,请使用 CacheBuilder
。
use mini_moka::sync::Cache;
use std::time::Duration;
fn main() {
let cache = Cache::builder()
// Time to live (TTL): 30 minutes
.time_to_live(Duration::from_secs(30 * 60))
// Time to idle (TTI): 5 minutes
.time_to_idle(Duration::from_secs( 5 * 60))
// Create the cache.
.build();
// This entry will expire after 5 minutes (TTI) if there is no get().
cache.insert(0, "zero");
// This get() will extend the entry life for another 5 minutes.
cache.get(&0);
// Even though we keep calling get(), the entry will expire
// after 30 minutes (TTL) from the insert().
}
关于过期策略的说明
如果配置了超过 1000 年的 time_to_live
或 time to idle
,缓存构建器将引发恐慌。这是为了防止在计算键过期时溢出。
最低支持的Rust版本
Mini Moka 最低支持的 Rust 版本(MSRV)如下
特性 | MSRV |
---|---|
默认特性 | Rust 1.61.0(2022 年 5 月 19 日) |
它将保持至少 6 个月的滚动 MSRV 政策。如果仅启用默认特性,MSRV 将保守更新。当使用其他特性时,MSRV 可能会更新得更频繁,直到最新的稳定版本。在两种情况下,增加 MSRV 都不会被视为 semver 破坏性更改。
开发Mini Moka
运行所有测试
要运行所有测试,包括 README 中的文档测试,请使用以下命令
$ RUSTFLAGS='--cfg skeptic --cfg trybuild' cargo test --all-features
生成文档
$ cargo +nightly -Z unstable-options --config 'build.rustdocflags="--cfg docsrs"' \
doc --no-deps
鸣谢
咖啡因
Mini Moka 的架构受到了 Java 库 Caffeine 的极大启发。感谢 Ben Manes 和所有 Caffeine 贡献者。
许可证
Mini Moka 可以选择以下其中一种许可证进行分发
- MIT 许可证
- Apache 许可证(版本 2.0)
由您选择。
有关详细信息,请参阅 LICENSE-MIT 和 LICENSE-APACHE。
依赖项
~0.5–5.5MB
~14K SLoC