为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
ITMISS 2022-09-05 10:14:38
假设我有一个昂贵的功能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 中模拟静态成员缓存的好方法是什么?
查看完整描述

3 回答

?
慕丝7291255

TA贡献1859条经验 获得超6个赞

您可以使用闭包;并让闭包管理缓存。


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:

4

from cache

4


veryExpensiveFunctionCached := InitExpensiveFuncWithCache()

并将包装的函数与代码一起使用。你可以在这里试试。


如果希望它是可重用的,请将签名更改为接受函数作为参数。将其包装在闭包中,用它替换昂贵的计算部分。InitExpensiveFuncWithCache(func(int) int)


查看完整回答
反对 回复 2022-09-05
?
慕雪6442864

TA贡献1812条经验 获得超5个赞

如果要在 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){

        

    })

}


查看完整回答
反对 回复 2022-09-05
?
呼啦一阵风

TA贡献1802条经验 获得超6个赞

Go 标准库使用以下样式来提供“静态”函数(例如,标志。命令行),但利用基础状态:


// "static" function is just a wrapper

func 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)


查看完整回答
反对 回复 2022-09-05
  • 3 回答
  • 0 关注
  • 138 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号