Golang 并发非阻塞缓存

《The Go Programming Language》笔记

import "sync"

type Func func(key string) (interface{}, error)

type result struct {
    value interface{}
    err   error
}

type entry struct {
    res result
    ready chan struct{} //closed when res is ready
}

type MemoryCache struct {
    f     Func
    mu    sync.Mutex
    cache map[string]*entry
}

func New(f Func) *MemoryCache {
    return &MemoryCache{f: f, cache: make(map[string]*entry)}
}

//获取互斥锁来保护共享变量cache map,查询map中是否存在指定key的value
//如果不存在那么分配空间插入新值,释放互斥锁。
//如果存在且其值没有写入完即其他goroutine在调用f这个慢函数,
//goroutine必须等待值ready之后才能读到key的value
//如果没有key对应的value,需要向map中插入一个没有ready的entry,
//当前正在调用的goroutine就需要负责调用慢函数更新result以及向其他goroutine
//广播(关闭ready)result已经可读了
func (mc *MemoryCache) Get(key string) (interface{}, error) {
    mc.mu.Lock()
    e := mc.cache[key]
    if e == nil { //e为空
        //This is the first request for this key
        e = &entry{ready:make(chan struct{})}
        mc.cache[key] = e
        mc.mu.Unlock()

        e.res.value, e.res.err = mc.f(key) //执行耗时函数
        close(e.ready)//broadcast ready condition
    }else {
        mc.mu.Unlock()
        <-e.ready //阻塞,直到ready关闭
    }
    return e.res.value, e.res.err
}
type Func func(key string) (interface{}, error)

type result struct {
    value interface{}
    err   error
}

type entry struct {
    res   result
    ready chan struct{} //closed when res is ready
}

type request struct {
    key      string
    response chan<- result
}

type MemoryCache struct {
    requests chan request
}

func New(f Func) *MemoryCache {
    mc := &MemoryCache{requests: make(chan request)}
    go mc.server(f)
    return mc
}

func (mc *MemoryCache) Get(key string) (interface{}, error) {
    response := make(chan result)
    mc.requests <- request{key, response}
    res := <- response
    return res.value, res.err
}

func (mc *MemoryCache) server(f Func) {
    cache := make(map[string]*entry)
    for req := range mc.requests {
        e := cache[req.key]
        if e == nil {
            e = &entry{ready: make(chan struct{})}
            cache[req.key] = e
            go e.call(f, req.key)
        }
        go e.deliver(req.response)

    }
}

func (mc *MemoryCache) Close()  {
    close(mc.requests)
}

func (e *entry) call(f Func, key string) {
    e.res.value, e.res.err = f(key)
    close(e.ready)
}

func (e *entry) deliver(response chan<- result) {
    <-e.ready         //wait for the ready condition
    response <- e.res //Send the result to the client
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值