以下代码中,getFunc 只支持一个参数,但我想支持多个参数。
(反射可以实现,但是不想用反射)
只基于 generic 还能进一步抽象支持多参数不?
package cache
import (
"sync"
"testing"
)
type CacheFn[K comparable, V any] struct {
redisMap sync.Map
routineOnceMap sync.Map
getFunc func(K) V
}
func NewCacheFn[K comparable, V any](getFunc func(K) V) *CacheFn[K, V] {
return &CacheFn[K, V]{getFunc: getFunc}
}
// 1. 执行缓存到 redisMap 或其它存储; 2.如果多个协程同时执行时,只执行一次(其它协程被阻塞)
func (c *CacheFn[K, V]) Get(key K) V {
value, ok := c.redisMap.Load(key)
if ok {
return value.(V)
} else {
var once sync.Once
onceInterface, loaded := c.routineOnceMap.LoadOrStore(key, &once)
if loaded { // 如果有其它协程在执行,则等待它结束
oncePtr := onceInterface.(*sync.Once)
oncePtr.Do(func() {})
} else { // 第一次访问,进行 DB 查询
once.Do(func() {
value = c.getFunc(key)
c.redisMap.Store(key, value)
})
}
val, _ := c.redisMap.Load(key)
return val.(V)
}
}
func TestCacheFuncWrapperGeneric(t *testing.T) {
type UserInfo struct {
Name string
Age int
}
// 原始函数
getUserInfoFromDb := func(name string) UserInfo {
println("get info from db:", name)
return UserInfo{Name: name}
}
// 带缓存的函数
getUserInfoFromDbWithCache := NewCacheFn(getUserInfoFromDb) // getFunc 只接受一个参数,怎么接收多个参数呢?
// 多个协程同时执行
batchCall := func(t *testing.T, fn func()) {
var wg sync.WaitGroup
for k := 0; k < 10; k++ {
wg.Add(1)
go func(i int) {
fn()
wg.Done()
}(k)
}
wg.Wait()
}
// 多次调用函数, 只执行一次
batchCall(t, func() {
userinfo := getUserInfoFromDbWithCache.Get("alex")
t.Log(userinfo)
})
}
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.