代码之家  ›  专栏  ›  技术社区  ›  Fabricio

理解原子加法和互斥

go
  •  3
  • Fabricio  · 技术社区  · 7 年前

    itemID 在下面的处理程序func中,有时增量会跳过一个值(例如: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)
        })
    }
    

    我使用互斥锁解决了这个问题:

    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)
        })
    }
    

    1 回复  |  直到 7 年前
        1
  •  3
  •   ssemilla    7 年前

    atomic.AddInt32() 对于多个goroutine并发使用来说是非常好的。这就是为什么它在 atomic 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 ,您现在可以将初始代码用于 原子.AddInt32() . 然而,我想指出的是,你不能阅读 项目