7 个不稳定版本
0.4.0 | 2024年3月7日 |
---|---|
0.3.1 | 2023年11月27日 |
0.3.0 | 2023年5月16日 |
0.2.2 | 2023年4月17日 |
0.1.0 | 2022年10月15日 |
#385 在 缓存 中
5,107 每月下载量
在 34 个 Crates 中使用(通过 comemo)
29KB
497 行
comemo
通过约束式缓存实现增量计算。
[dependencies]
comemo = "0.4"
一个被缓存的函数会缓存它的返回值,这样它就只需要对一组唯一的参数执行一次。这使得它成为一个非常好的优化工具。然而,基本的缓存机制相当有限。对于像增量编译器这样的更高级使用案例,它缺乏必要的粒度。考虑,例如,简单 .calc
脚本语言的情况。这种语言中的脚本由数字之和和 eval
语句组成,这些语句引用其他 .calc
脚本。一些例子包括
alpha.calc
:"2 + eval beta.calc"
beta.calc
:"2 + 3"
gamma.calc
:"8 + 3"
我们可以轻松编写一个计算 .calc
文件输出的解释器
/// Evaluate a `.calc` script.
fn evaluate(script: &str, files: &Files) -> i32 {
script
.split('+')
.map(str::trim)
.map(|part| match part.strip_prefix("eval ") {
Some(path) => evaluate(&files.read(path), files),
None => part.parse::<i32>().unwrap(),
})
.sum()
}
impl Files {
/// Read a file from storage.
fn read(&self, path: &str) -> String {
...
}
}
但是,如果我们想使这个解释器 增量,也就是说,只有当它或其依赖项发生变化时才重新计算脚本的结果,该怎么办?基本的缓存机制无法帮助我们,因为解释器需要整个文件集作为输入——这意味着任何文件的变化都会使所有缓存的计算结果无效。
这就是 comemo 发挥作用的地方。它实现了具有更细粒度访问跟踪的 约束式缓存。要使用它,我们只需
- 将
#[memoize]
属性添加到evaluate
函数。 - 将
#[track]
属性添加到Files
的 impl 块中。 - 将
files
参数封装在 comemo 的Tracked
容器中。
这指示 comemo 缓存评估结果并在缓存调用期间自动跟踪所有文件访问。因此,只要其依赖项保持不变,就可以重复使用 .calc
脚本评估的结果——即使其他文件已更改。
use comemo::{memoize, track, Tracked};
/// Evaluate a `.calc` script.
#[memoize]
fn evaluate(script: &str, files: Tracked<Files>) -> i32 {
...
}
#[track]
impl Files {
/// Read a file from storage.
fn read(&self, path: &str) -> String {
...
}
}
完整示例请见 examples/calc.rs
。
许可证
此软件包同时受 MIT 和 Apache 2.0 许可证的许可。
依赖项
~305–760KB
~18K SLoC