【问题标题】:What is the idiomatic way to implement caching on a function that is not a struct method?在不是结构方法的函数上实现缓存的惯用方法是什么?
【发布时间】:2016-03-26 02:16:00
【问题描述】:

我有这样一个昂贵的功能:

pub fn get_expensive_value(n: u64): u64 {
   let ret = 0;
   for 0 .. n {
       // expensive stuff
   }
   ret
}

而且它被非常频繁地使用相同的参数调用。它是纯粹的,这意味着它将返回相同的结果并且可以使用缓存。

如果这是一个结构体方法,我会在结构体中添加一个成员作为缓存,但事实并非如此。所以我的选择似乎是使用静态:

static mut LAST_VAL: Option<(u64, u64)> = None;

pub fn cached_expensive(n: u64) -> u64 {
   unsafe {
       LAST_VAL = LAST_VAL.and_then(|(k, v)| {
           if k == n {
              Some((n,v))
           } else {
              None
           }
       }).or_else(|| {
           Some((n, get_expensive_value(n)))
       });
       let (_, v) = LAST_VAL.unwrap();
       v
   }
}

现在,我不得不使用unsafe。代替static mut,我可以将RefCell 放入const。但我不相信这更安全 - 它只是避免使用 unsafe 块。我想过Mutex,但我认为这也不会让我获得线程安全。

重新设计代码以使用结构进行存储并不是一个真正的选择。

【问题讨论】:

  • 或者您可以更改cached_expensive 的签名以接受缓存作为另一个参数。
  • 我不认为这是重复的。我的问题是专门关于缓存的,虽然我的出发点是一个全局的、可变的单例,但这是偶然的,一个好的解决方案可能会解释(例如)RefCellMutex 如何使它变得更好,或者提供一个完全结构上不同的选择。
  • 我不同意,但在其他人同意我之前,我不会使用魔法dupehammer。简而言之,没有其他地方可以存储数据。您要么传入一个存储位置(通过显式参数或通过self 隐式传递),要么必须将其存储在全局存储中。后者的限制是您需要处理对缓存的并发访问。
  • 虽然我现在还不能完全推理出来,但我觉得问题中提议的 unsafe 块不支持所需的安全保证。例如,我很确定对函数的并发调用可以对存储进行部分读取/写入(因为没有互斥),从而在任意情况下导致奇怪的行为。

标签: caching rust static-members


【解决方案1】:

我认为最好的选择是使用带有互斥锁的全局变量。使用lazy_static 很容易,并允许在函数内部进行“全局”声明

pub fn cached_expensive(n: u64) -> u64 {
    use std::sync::Mutex;
    lazy_static! {
        static ref LAST_VAL: Mutex<Option<(u64, u64)>> = Mutex::new(None);
    }
    let mut last = LAST_VAL.lock().unwrap();
    let r = last.and_then(|(k, v)| {
        if k == n {
            Some((n, v))
        } else {
            None
        }
    }).or_else(|| Some((n, get_expensive_value(n))));
    let (_, v) = r.unwrap();
    *last = r;
    v
}

【讨论】:

【解决方案2】:

您还可以查看cached 项目/板条箱。它用一个简单的宏来记忆函数。

【讨论】:

    猜你喜欢
    • 2022-08-18
    • 1970-01-01
    • 1970-01-01
    • 2014-06-23
    • 2015-10-23
    • 1970-01-01
    • 2015-07-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多