有没有更好的方法使用通道来确保对地图的同步访问?

huangapple go评论82阅读模式
英文:

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(&quot;sesstoken&quot;)

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 = &lt;-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] = &lt;-sdc
	}

// Is this necessary? Is there a better way?
// ---------------------------------------		
	if sd == nil {
		sdc = make(chan *session.SessionData, 1)
		go session.GetSessionFromCache(sessTkn, sdc)
		sd = &lt;-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 := &amp;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 &quot;sync&quot;

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) 

huangapple
  • 本文由 发表于 2017年5月30日 11:16:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/44252852.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定