我如何概括这个 map + sync.RWMutex 模式?
How can I generalize this map + sync.RWMutex pattern?
考虑到 go 中没有泛型,我如何概括这个映射 access/modification 模式?
func (pool *fPool) fetch(url string) *ResultPromise {
pool.cacheLock.RLock()
if rp, pres := pool.cache[url]; pres {
pool.cacheLock.RUnlock()
return rp
}
pool.cacheLock.RUnlock()
pool.cacheLock.Lock()
if rp, pres := pool.cache[url]; pres {
pool.cacheLock.Unlock()
// Skip adding url if someone snuck it in between RUnlock an Lock
return rp
}
rp := newPromise()
pool.cache[url] = rp
pool.cacheLock.Unlock()
pool.c <- fetchWork{rp, url} // Expensive/atomic work
return rp
}
出于显而易见的原因,它用于多个不同类型的地图。
也许这是一个糟糕的解决方案?
免责声明:这与 中的代码相同,抱歉。
既然泛型可用,我决定重新访问 Go,并回答我的问题。这是我想出的:
type Cached[K comparable, R any] struct {
cache map[K]R
fn func(K) R
lock sync.RWMutex
}
func NewCached[K comparable, R any](
fn func(K) R) *Cached[K, R] {
return &Cached[K, R]{
cache: make(map[K]R),
fn: fn,
lock: sync.RWMutex{},
}
}
func (c *Cached[K, R]) Get(k K) R {
c.lock.RLock()
if rp, pres := c.cache[k]; pres {
c.lock.RUnlock()
return rp
}
c.lock.RUnlock()
c.lock.Lock()
defer c.lock.Unlock()
if rp, pres := c.cache[k]; pres {
// Skip adding key if someone else snuck it in between RUnlock and Lock
return rp
}
rp := c.fn(k)
c.cache[k] = rp
return rp
}
考虑到 go 中没有泛型,我如何概括这个映射 access/modification 模式?
func (pool *fPool) fetch(url string) *ResultPromise {
pool.cacheLock.RLock()
if rp, pres := pool.cache[url]; pres {
pool.cacheLock.RUnlock()
return rp
}
pool.cacheLock.RUnlock()
pool.cacheLock.Lock()
if rp, pres := pool.cache[url]; pres {
pool.cacheLock.Unlock()
// Skip adding url if someone snuck it in between RUnlock an Lock
return rp
}
rp := newPromise()
pool.cache[url] = rp
pool.cacheLock.Unlock()
pool.c <- fetchWork{rp, url} // Expensive/atomic work
return rp
}
出于显而易见的原因,它用于多个不同类型的地图。
也许这是一个糟糕的解决方案?
免责声明:这与
既然泛型可用,我决定重新访问 Go,并回答我的问题。这是我想出的:
type Cached[K comparable, R any] struct {
cache map[K]R
fn func(K) R
lock sync.RWMutex
}
func NewCached[K comparable, R any](
fn func(K) R) *Cached[K, R] {
return &Cached[K, R]{
cache: make(map[K]R),
fn: fn,
lock: sync.RWMutex{},
}
}
func (c *Cached[K, R]) Get(k K) R {
c.lock.RLock()
if rp, pres := c.cache[k]; pres {
c.lock.RUnlock()
return rp
}
c.lock.RUnlock()
c.lock.Lock()
defer c.lock.Unlock()
if rp, pres := c.cache[k]; pres {
// Skip adding key if someone else snuck it in between RUnlock and Lock
return rp
}
rp := c.fn(k)
c.cache[k] = rp
return rp
}