猿问

将缓存添加到 go 函数中,就好像它是静态成员一样

假设我有一个昂贵的功能


func veryExpensiveFunction(int) int

并且对于相同的数字,此函数被调用很多。


有没有一种好方法可以允许这个函数存储以前的结果,以便在再次调用该函数时使用,甚至可能对非常消耗的函数2重用?


显然,可以添加一个参数


func veryExpensiveFunctionCached(p int, cache map[int]int) int {

    if val, ok := cache[p]; ok {

        return val

    }

    result := veryExpensiveFunction(p)

    cache[p] = result

    return result

}

但是现在我必须在某个地方创建缓存,在那里我不关心它。如果可能的话,我宁愿将其作为“静态函数成员”。


在 go 中模拟静态成员缓存的好方法是什么?


ITMISS
浏览 139回答 3
3回答

慕丝7291255

您可以使用闭包;并让闭包管理缓存。func InitExpensiveFuncWithCache() func(p int) int {    var cache = make(map[int]int)    return func(p int) int {        if ret, ok := cache[p]; ok {            fmt.Println("from cache")            return ret        }        // expensive computation        time.Sleep(1 * time.Second)        r := p * 2        cache[p] = r        return r    }}func main() {    ExpensiveFuncWithCache := InitExpensiveFuncWithCache()        fmt.Println(ExpensiveFuncWithCache(2))    fmt.Println(ExpensiveFuncWithCache(2))}output:4from cache4veryExpensiveFunctionCached := InitExpensiveFuncWithCache()并将包装的函数与代码一起使用。你可以在这里试试。如果希望它是可重用的,请将签名更改为接受函数作为参数。将其包装在闭包中,用它替换昂贵的计算部分。InitExpensiveFuncWithCache(func(int) int)

慕雪6442864

如果要在 http 处理程序中使用此缓存,则需要小心同步。在 Go 标准 lib 中,每个 http 请求都在专用的 goroutine 中处理,此时我们处于并发和争用条件的领域。我建议使用RWMutex来确保数据一致性。至于缓存注入,您可以在创建http处理程序的函数中注入它。这是一个原型type Cache struct {    store map[int]int    mux   sync.RWMutex}func NewCache() *Cache {    return &Cache{make(map[int]int), sync.RWMutex{}}}func (c *Cache) Set(id, value int) {    c.mux.Lock()    c.store[id] = id    c.mux.Unlock()}func (c *Cache) Get(id int) (int, error) {    c.mux.RLock()    v, ok := c.store[id]    c.mux.RUnlock()    if !ok {        return -1, errors.New("a value with given key not found")    }    return v, nil}func handleComplexOperation(c *Cache) http.HandlerFunc {    return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request){            })}

呼啦一阵风

Go 标准库使用以下样式来提供“静态”函数(例如,标志。命令行),但利用基础状态:// "static" function is just a wrapperfunc Lookup(p int) int { return expCache.Lookup(p) }var expCache = NewCache()func newCache() *CacheExpensive { return &CacheExpensive{cache: make(map[int]int)} }type CacheExpensive struct {    l     sync.RWMutex // lock for concurrent access    cache map[int]int}func (c *CacheExpensive) Lookup(p int) int { /*...*/ }这种设计模式不仅允许简单的一次性使用,而且还允许隔离使用:var (    userX = NewCache()    userY = NewCache())userX.Lookup(12)userY.Lookup(42)
随时随地看视频慕课网APP

相关分类

Go
我要回答