我正在下面的处理程序函数中测试递增itemID
的并发性,有时递增会跳过一个值(例如:4、6、7 ...跳过了ID 5)。
func proxyHandler() http.Handler {
var itemID int32
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
proxy := httputil.NewSingleHostReverseProxy(url)
proxy.ModifyResponse = func(res *http.Response) error {
item := Item{
ID: int(atomic.AddInt32(&itemID, 1)),
}
items.Add(item)
return nil
}
proxy.ServeHTTP(rw, req)
})
}
我使用Mutex解决了该问题:
func proxyHandler() http.Handler {
itemID := 0
mux := sync.Mutex{}
return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
proxy := httputil.NewSingleHostReverseProxy(url)
proxy.ModifyResponse = func(res *http.Response) error {
mux.Lock()
itemID++
item := Item{
ID: itemID,
}
items.Add(item)
mux.Unlock()
return nil
}
proxy.ServeHTTP(rw, req)
})
}
我想了解为什么原子加法不如我所期望的那样起作用,即生成没有间隙的连续值。
答案 0 :(得分:3)
atomic.AddInt32()
非常适合多个goroutine并发使用。这就是为什么它位于atomic
包中的原因。您遇到的问题是Items.Add()
,您在评论中指出该锁定没有任何锁定保护。
这是一个安全的Items.Add()
type Items struct {
items []Item
lock sync.Mutex
}
func (i *Items) Add(item Item) {
i.lock.Lock()
defer i.lock.Unlock()
i.items = append(i.items, item)
}
有了以上Items
的定义,您现在可以将初始代码与atomic.AddInt32()
一起使用。但是,我想指出的是,当其他线程附加到Items
上时,请勿阅读。甚至读取也必须同步。