App 2.0开发模式的行业看法
802
2022-11-06
【每周一库】- cached - 缓存结构型、辅助函数记忆化
cached
缓存结构型,简化函数记忆化
cached 提供几种不同缓存结构型的实现和一个易用的用作定义记忆化函数的宏,可为动态规划算法的实现带来很大的便利
使用#[cached]/cached!宏定义的记忆化函数具有线程安全的特性,并自带封装在互斥锁中的后备函数缓存。函数缓存在函数执行期间是非锁定状态,因此,具有相同参数的长期运行函数的初始(在空缓存上)并发调用将被完整执行,并且每次完成时都会覆盖已记忆值。这与Python的functools.lru_cache行为相同
用#[cached] & cached!宏定义记忆化函数
基本使用案例:
use cached::proc_macro::cached;/// 定义一个叫`fib`的函数,此函数使用一个名为`FIB`的缓存/// 默认情况下,缓存的名称与函数相同,但用全大写字母命名/// 下一行代码与#[cached(name = "FIB", unbound)]效果相同#[cached]fn fib(n: u64) -> u64 {if n == 0 || n == 1 { return n } fib(n-1) + fib(n-2)}use std::thread::sleep;use std::time::Duration;use cached::proc_macro::cached;/// 使用一个大小为100的lru(最近最少使用)缓存和一个类型为 `(String, String)` 的缓存键#[cached(size=100)]fn keyed(a: String, b: String) -> usize {let size = a.len() + b.len(); sleep(Duration::new(size as u64, 0)); size}use std::thread::sleep;use std::time::Duration;use cached::proc_macro::cached;use cached::SizedCache;/// 将`显式缓存类型`与`自定义创建块`和`自定义缓存键生成块`一起使用#[cached( type = "SizedCache
使用#[cached]/cached!定义的函数将使用函数的参数作为键来缓存其结果(在使用cached_key!时则是一个特定的表达式)。当用 cached! 定义的函数被调用时,在运行函数逻辑之前,首先会检查函数的缓存中是否存在已计算(并且仍然有效)的结果。
出于在全局缓存中存储参数和返回值的需要:
函数返回类型必须被拥有并实现Clone函数参数必须被拥有并且实现 Hash + Eq + Clone 或者使用 cached_key! 宏来将参数转换为一个被拥有的 Hash + Eq + Clone 类型在插入和检索过程中,参数和返回值将被克隆请勿使用#[cached]/cached! 函数来产生 side-effectual 的结果!因为cached!会被扩展为once_cell 初始化和函数定义,所以#[cached]/cached! 函数不能直接存在于impl块下#[cached]/cached! 函数不能接受类型为 Self 的参数
注意: 任何实现cached :: Cached的自定义缓存都可以与cached宏一起使用,以代替内置函数。
cached! 和cached_key! 用法与选项:
有多种选择,具体取决于您想要的显示方式。有关完整的语法细分,请参见以下代码:
1.) 使用简写将使用无限制的缓存。
#[macro_use] extern crate cached;/// 定义一个名为`fib`的函数并使用一个名为`FIB`的缓存cached!{ FIB;fn fib(n: u64) -> u64 = {if n == 0 || n == 1 { return n } fib(n-1) + fib(n-2) }}
2.) 使用完整语法需要指定完整的缓存类型并提供要使用的缓存实例。请注意,缓存的键类型是函数参数类型的元组。如果您希望对键进行精细控制,可以使用 cached_key! 宏。以下用例使用 SizedCache (LRU):
#[macro_use] extern crate cached;use std::thread::sleep;use std::time::Duration;use cached::SizedCache;/// 定义一个使用名为`COMPUTE`、大小限制为50的LRU缓存的名为`compute`的函数/// `cached!`宏将隐式地将函数参数组合成一个元组,以用作缓存键cached!{ COMPUTE: SizedCache<(u64, u64), u64> = SizedCache::with_size(50);fn compute(a: u64, b: u64) -> u64 = { sleep(Duration::new(2, 0));return a * b; }}
3.) cached_key宏的功能相同,但是允许将缓存键定义为表达式。
#[macro_use] extern crate cached;use std::thread::sleep;use std::time::Duration;use cached::SizedCache;/// 定义一个名为`length`的函数并使用一个名为`LENGTH`的LRU作为其缓存/// `Key = ` 表达式用作显式定义将被用作缓存键使用的值/// 在这里,借用的参数将转换为被拥有的字符串,该字符串可以存储在全局函数缓存中cached_key!{ LENGTH: SizedCache
4.) cached_result 与 cached_key_result 宏的作用对应于 cached 和 cached_key 相类似,但是带有缓存的函数需要返回Result(或诸如 io::Result的类型别名)。如果函数返回Ok(val),那么val会被缓存,但报错会不同。注意只有成功时的返回类型需要实现Clone, 错误时的返回类型则不需要。当使用cached_result和cached_key_result时,缓存的类型不能被派生,必须要明确指定。
#[macro_use] extern crate cached;use cached::UnboundCache;/// 缓存函数成功时的返回/// 使用`cached_key_result`与使用`cached_key`时一样添加一个键函数cached_result!{ MULT: UnboundCache<(u64, u64), u64> = UnboundCache::new(); // 类型必须被指定fn mult(a: u64, b: u64) -> Result
语法
常用的宏语法如下:
cached_key!{ CACHE_NAME: CacheType = CacheInstance; Key = KeyExpression;fn func_name(arg1: arg_type, arg2: arg_type) -> return_type = { return_type }}
其中:
细粒度控制可使用 cached_control!
cached_control!宏允许提供插入到记忆化函数的关键区域中的表达式。尽管cached和cached_result变体可以应付大多数情况,但需要自定义宏的功能时会很有用。
#[macro_use] extern crate cached;use cached::UnboundCache;/// 以下的用例使用插入式表达式实现与`cached_result!`功能类似的宏cached_control!{ CACHE: UnboundCache
许可证: MIT
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。