我使用Go map作为内存缓存和通道来确保同步访问。
我的“session”包将缓存定义为:map [string] * SessionData
SessionData是一个在包中定义的结构,以及代码中所见的其他访问函数。
GetWebPage(rw http.ResponseWriter, req *http.Request) {
var sd *session.SessionData
var sessTkn string
cookie, err := req.Cookie("sesstoken")
if err == nil { // cookie found
sessTkn = cookie.Value
// Check for cache entry for this token,
// using a channel to protect the map and return
// a pointer to the cached data if it exists
sdc := make(chan *session.SessionData, 1)
go session.GetSessionFromCache(sessTkn, sdc)
sd = <-sdc
if sd == nil { // sessTkn not in the cache
// This is test data to simplify example
sv := make([]string, 4)
sv[0] = sessTkn
iv := make([]int, 3)
iv[0] = 100
iv[1] = 1000
sdc := make(chan *session.SessionData, 1)
go session.NewSessionData(sv, iv, false, false, sdc)
session.SC[sessTkn] = <-sdc
}
// Is this necessary? Is there a better way?
// ---------------------------------------
if sd == nil {
sdc = make(chan *session.SessionData, 1)
go session.GetSessionFromCache(sessTkn, sdc)
sd = <-sdc
}
// ---------------------------------------
fmt.Println(sd) // just to prove that it works in both cases
}
// The rest of the handler code follows
答案 0 :(得分:4)
使用mutex保护地图。互斥体通常比使用频道和放大器更简单。用于保护资源的goroutines。
var (
mu sync.Mutex
cache = make(map[string]*SessionData)
)
func GetSessionFromCache(sessTkn string) *SessionData {
mu.Lock()
defer mu.Unlock()
sd := cache[sessTkn]
if sd != nil {
return sd
}
sd := &SessionData{
// initialize new value here
}
cache[sessTkn] = sd
return sd
}
像这样使用:
sd := session.GetSessionFromCache(sessTkn)
答案 1 :(得分:1)
针对此特定案例使用渠道没有额外的好处。如果您考虑一下,即使创建新频道,您仍然只能有一个可以访问地图的goroutine。由于这里没有并发优势,只需使用sync.Mutex
。
package session
import "sync"
var cache = struct {
sync.Mutex
list map[string]*SessionData
}{
list: make(map[string]*SessionData),
}
func GetSessionFromCache(token string) *SessionData {
cache.Lock()
defer cache.Unlock()
return cache.list[token]
}
然后,不需要新的goroutine。直接调用它。
sd := session.GetSessionFromCache(sessTkn)