有没有更好的方法使用通道来确保同步访问地图?
Is there a better way to use channels to ensure synchronous access to the map?
我使用 Go 映射作为内存缓存和通道来确保同步访问。
我的 "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
使用mutex保护地图。互斥量通常比使用通道和协程来保护资源更简单。
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)
在这种特殊情况下使用渠道没有额外的好处。如果你想一想,即使创建了新的通道,你仍然只能有一个可以访问地图的 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)
我使用 Go 映射作为内存缓存和通道来确保同步访问。
我的 "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
使用mutex保护地图。互斥量通常比使用通道和协程来保护资源更简单。
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)
在这种特殊情况下使用渠道没有额外的好处。如果你想一想,即使创建了新的通道,你仍然只能有一个可以访问地图的 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)