英文:
Is there a better way to use channels to ensure synchronous access to the map?
问题
我正在使用Go maps作为内存缓存,并使用通道来确保同步访问。
我的"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
sessTkn = cookie.Value
// 检查此令牌的缓存条目,
// 使用通道保护映射并返回
// 如果存在,则返回指向缓存数据的指针
sdc := make(chan *session.SessionData, 1)
go session.GetSessionFromCache(sessTkn, sdc)
sd = <-sdc
if sd == nil { // 缓存中没有sessTkn
// 这是为了简化示例而使用的测试数据
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
}
// 这是必要的吗?有更好的方法吗?
// ---------------------------------------
if sd == nil {
sdc = make(chan *session.SessionData, 1)
go session.GetSessionFromCache(sessTkn, sdc)
sd = <-sdc
}
// ---------------------------------------
fmt.Println(sd) // 只是为了证明它在两种情况下都起作用
}
// 其余的处理程序代码如下
英文:
I'm using Go maps as an in memory cache and channels to ensure synchronous access.
My "session" package defines the cache as: map[string]*SessionData
SessionData is a struct also defined in the package, along with other access functions as seen in the code.
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
答案1
得分: 4
使用互斥锁来保护地图。互斥锁通常比使用通道和goroutine来保护资源更简单。
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{
// 在这里初始化新值
}
cache[sessTkn] = sd
return sd
}
像这样使用它:
sd := session.GetSessionFromCache(sessTkn)
英文:
Use a mutex to protect the map. A mutex is often simpler than using channels & goroutines to protect a resource.
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
}
Use it like this:
sd := session.GetSessionFromCache(sessTkn)
答案2
得分: 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)
英文:
Using channels for this particular case have no additional benefit. If you think about it, even with creating new channels, you can still only have one goroutine that can access the map. Since there is no concurrency benefit here, just use 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]
}
Then, no need for a new goroutine. Just call it directly.
sd := session.GetSessionFromCache(sessTkn)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论