19个版本
0.4.2 | 2023年12月23日 |
---|---|
0.4.1 | 2023年10月27日 |
0.4.0 | 2023年1月18日 |
0.3.3 | 2022年12月2日 |
0.1.4 | 2020年10月16日 |
#19 在 缓存
每月下载量 13,869
在 14 个 Crates 中使用 (7 直接)
10KB
memoize
#[memoize]
属性,用于相对简单的 Rust 函数:也就是说,具有一个或多个可 Clone
的参数,以及一个可 Clone
的返回类型。就是这样。
更新日志:该包已更新,因此您不需要单独导入 lru
、lazy_static
和其他依赖项。现在应该可以自动工作。请记住启用 full
功能以使用 LRU 缓存和其他附加功能。
阅读文档 (cargo doc --open
) 以获取详细信息,或查看 examples/
,以了解更多信息
// From examples/test2.rs
use memoize::memoize;
#[memoize]
fn hello(arg: String, arg2: usize) -> bool {
arg.len()%2 == arg2
}
fn main() {
// `hello` is only called once here.
assert!(! hello("World".to_string(), 0));
assert!(! hello("World".to_string(), 0));
// Sometimes one might need the original function.
assert!(! memoized_original_hello("World".to_string(), 0));
}
这可以扩展为(进行了一些简化)
std::thread_local! {
static MEMOIZED_MAPPING_HELLO : RefCell<HashMap<(String, usize), bool>> = RefCell::new(HashMap::new());
}
pub fn memoized_original_hello(arg: String, arg2: usize) -> bool {
arg.len() % 2 == arg2
}
#[allow(unused_variables)]
fn hello(arg: String, arg2: usize) -> bool {
let ATTR_MEMOIZE_RETURN__ = MEMOIZED_MAPPING_HELLO.with(|ATTR_MEMOIZE_HM__| {
let mut ATTR_MEMOIZE_HM__ = ATTR_MEMOIZE_HM__.borrow_mut();
ATTR_MEMOIZE_HM__.get(&(arg.clone(), arg2.clone())).cloned()
});
if let Some(ATTR_MEMOIZE_RETURN__) = ATTR_MEMOIZE_RETURN__ {
return ATTR_MEMOIZE_RETURN__;
}
let ATTR_MEMOIZE_RETURN__ = memoized_original_hello(arg.clone(), arg2.clone());
MEMOIZED_MAPPING_HELLO.with(|ATTR_MEMOIZE_HM__| {
let mut ATTR_MEMOIZE_HM__ = ATTR_MEMOIZE_HM__.borrow_mut();
ATTR_MEMOIZE_HM__.insert((arg, arg2), ATTR_MEMOIZE_RETURN__.clone());
});
r
}
其他功能
如上例所示,默认情况下,每个线程都有自己的缓存。如果您希望每个线程共享相同的缓存,可以像下面这样指定 SharedCache
选项,以将缓存包装在 std::sync::Mutex
中。例如
#[memoize(SharedCache)]
fn hello(key: String) -> ComplexStruct {
// ...
}
您可以选择使用 LRU 缓存。实际上,如果您知道 memoized 函数具有无界数量的不同输入,您应该这样做!在这种情况下,使用如下属性
// From examples/test1.rs
// Compile with --features=full
use memoize::memoize;
#[derive(Debug, Clone)]
struct ComplexStruct {
// ...
}
#[memoize(Capacity: 123)]
fn hello(key: String) -> ComplexStruct {
// ...
}
添加更多缓存和配置选项相对简单,只是解析属性参数的问题。目前,如果您未启用 full
功能而使用例如 Capacity
参数,则编译将失败。
另一个参数是 TimeToLive,指定缓存值可以存在多长时间
#[memoize(Capacity: 123, TimeToLive: Duration::from_secs(2))]
chrono::Duration
也是可能的,但首先必须将其转换为 std::time::Duration
#[memoize(TimeToLive: chrono::Duration::hours(3).to_std().unwrap())]
缓存值将永远不会超过提供的持续时间,而是在下一次请求时重新计算。
您还可以指定一个 自定义哈希器,例如使用 CustomHasher
的 AHash。
#[memoize(CustomHasher: ahash::HashMap)]
由于一些散列函数初始化的不是 new()
,您可以指定一个 HasherInit
函数调用。
#[memoize(CustomHasher: FxHashMap, HasherInit: FxHashMap::default())]
有时,您可能无法或不希望将数据作为缓存的一部分存储。在这些情况下,您可以在 #[memoize]
宏中使用 Ignore
参数来忽略一个参数。任何被 Ignore
的参数不再需要是 Clone
-able 的,因为它们不是作为参数集的一部分存储的,并且更改一个 Ignore
的参数不会触发再次调用函数。您可以通过多次指定 Ignore
参数来忽略多个参数。
// `Ignore: count_calls` lets our function take a `&mut u32` argument, which is normally not
// possible because it is not `Clone`-able.
#[memoize(Ignore: count_calls)]
fn add(a: u32, b: u32, count_calls: &mut u32) -> u32 {
// Keep track of the number of times the underlying function is called.
*count_calls += 1;
a + b
}
刷新
如果您对函数 f
进行了记忆化,将会有一个名为 memoized_flush_f()
的函数,允许您清除记忆化缓存。
贡献
...总是受欢迎的!这是我第一个过程宏存储库,我对功能和风格的改进表示感激。请发送一个拉取请求,如果我的审查需要一段时间,请不要气馁;我有时在这里有点慢 :) -- Lewin
依赖关系
~1.2–1.8MB
~40K SLoC