假设我有一个可以并发访问地图的程序,如下所示:
func getKey(r *http.Request) string { ... }
values := make(map[string]int)
http.HandleFunc("/get", func(w http.ResponseWriter, r *http.Request) {
key := getKey(r)
fmt.Fprint(w, values[key])
})
http.HandleFunc("/set", func(w http.ResponseWriter, r *http.Request) {
key := getKey(r)
values[key] = rand.Int()
})
Run Code Online (Sandbox Code Playgroud)
这很糟糕,因为地图写入是非原子的.所以我可以使用读/写互斥锁
func getKey(r *http.Request) string { ... }
values := make(map[string]int)
var lock sync.RWMutex
http.HandleFunc("/get", func(w http.ResponseWriter, r *http.Request) {
key := getKey(r)
lock.RLock()
fmt.Fprint(w, values[key])
lock.RUnlock()
})
http.HandleFunc("/set", func(w http.ResponseWriter, r *http.Request) {
key := getKey(r)
lock.Lock()
values[key] = rand.Int()
lock.Unlock()
})
Run Code Online (Sandbox Code Playgroud)
这看起来很好,除了我们直接使用互斥体而不是通道.
实现这个的更实际的方法是什么?或者这是一个互联网真正需要的时代吗?
Ral*_*veo 11
我认为这个大小取决于你的表现期望以及最终如何使用这张地图.
当我研究同样的问题时,我遇到了这篇非常有用的文章,应该回答你的问题.
我个人的回答是,除非你真的发现需要使用互斥锁,否则你应该默认使用频道.惯用Go的核心点是,如果您坚持使用更高级别的通道功能,则不需要使用互斥锁并担心锁定.记住Go的座右铭:"通过沟通共享记忆,不要通过共享记忆来沟通."
还有一个细节,非常详细地介绍了在Mark Summerfield的Go书中建立一个安全地图以便同时使用的不同技术.
为了突出Rob Pike的幻灯片,Go的创造者之一:
并发简化了同步
- 不需要显式同步
- 程序的结构是隐式同步的
当你沿着使用像互斥体这样的原语的道路走下去时,由于你的程序更加复杂,这是非常非常难以做到的.你被警告了.
这里还引用了Golang网站本身:
由于实现对共享变量的正确访问所需的微妙之处,许多环境中的并发编程变得困难.Go鼓励采用一种不同的方法,在这种方法中,共享值在通道上传递,实际上,不会由单独的执行线程主动共享.在任何给定时间,只有一个goroutine可以访问该值.这种方法可以采取太多措施.例如,可以通过在整数变量周围放置互斥量来最好地完成引用计数.但作为一种高级方法,使用通道来控制访问可以更容易地编写清晰,正确的程序.
我会说互斥体适用于这个应用程序.将它们包裹在一个类型中,这样你就可以像以后一样改变主意.注意嵌入sync.RWMutex然后使锁定更整洁.
type thing struct {
sync.RWMutex
values map[string]int
}
func newThing() *thing {
return &thing{
values: make(map[string]int),
}
}
func (t *thing) Get(key string) int {
t.RLock()
defer t.RUnlock()
return t.values[key]
}
func (t *thing) Put(key string, value int) {
t.Lock()
defer t.Unlock()
t.values[key] = value
}
func main() {
t := newThing()
t.Put("hello", 1)
t.Put("sausage", 2)
fmt.Println(t.Get("hello"))
fmt.Println(t.Get("potato"))
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2968 次 |
| 最近记录: |