dreamact3026 2012-05-23 22:41
浏览 87
已采纳

在并发goroutine期间如何锁定/同步Go中对变量的访问?

In his answer to this question: Golang for Windows erratic behavior? user @distributed recommended to lock/synchronize access to a shared variable on concurrent goroutines.

How can I do that?

More on the issue:

I get this code (the returned function with a closure on views) running on several goroutines at the same time:

func makeHomeHandler() func(c *http.Conn, r *http.Request) {
    views := 1
    return func(c *http.Conn, r *http.Request) {
        fmt.Fprintf(c, "Counting %s, %d so far.", r.URL.Path[1:], views)
        views++
    }
}

It looks like the IO function takes it's time, and as a result I get this kind of output:

Counting monkeys, 5 so far.
Counting monkeys, 5 so far.
Counting monkeys, 5 so far.
Counting monkeys, 8 so far.
Counting monkeys, 8 so far.
Counting monkeys, 8 so far.
Counting monkeys, 11 so far.

It increments fine, but when it gets printed I can see that the operation printing+incrementing is not atomic at all.

If I change it to:

func makeHomeHandler() func(c *http.Conn, r *http.Request) {
    views := 0
    return func(c *http.Conn, r *http.Request) {
        views++
        // I can only hope that other goroutine does not increment the counter 
        // at this point, i.e., right after the previous line and before the 
        // next one are executed!
        views_now := views
        fmt.Fprintf(c, "Counting %s, %d so far.", r.URL.Path[1:], views_now)
    }
}

It seems to work fine, but I'm not completely sure if it will not fail eventually...

  • 写回答

2条回答 默认 最新

  • doulu1968 2012-05-24 10:34
    关注

    If a synchronized counter is all you want, then using sync.Mutex is the canonical solution. The sync/atomic package should only be used for low level stuff or when you've measured a serious performance problem.

    type Counter struct {
        mu  sync.Mutex
        x   int64
    }
    
    func (c *Counter) Add(x int64) {
        c.mu.Lock()
        c.x += x
        c.mu.Unlock()
    }
    
    func (c *Counter) Value() (x int64) {
        c.mu.Lock()
        x = c.x
        c.mu.Unlock()
        return
    }
    
    func makeHomeHandler() func(c http.ResponseWriter, r *http.Request) {
        var views Counter
        return func(w http.ResponseWriter, r *http.Request) {
            fmt.Fprintf(w, "Counting %s, %d so far.", r.URL.Path[1:], views.Value())
            views.Add(1)
        }
    }
    

    For your particular problem, I'd suggest defining a new type that satisfies the http.Handler interface, rather than returning a closure. That looks simpler too:

    type homeHandler struct {
        mu  sync.Mutex
        views   int64
    }
    
    func (h *homeHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
        h.mu.Lock()
        defer h.mu.Unlock()
        fmt.Fprintf(w, "Counting %s, %d so far.", r.URL.Path[1:], h.views)
        h.views++
    }
    
    func init() {
        http.Handle("/", new(homeHandler))
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 下图接收小电路,谁知道原理
  • ¥15 装 pytorch 的时候出了好多问题,遇到这种情况怎么处理?
  • ¥20 IOS游览器某宝手机网页版自动立即购买JavaScript脚本
  • ¥15 手机接入宽带网线,如何释放宽带全部速度
  • ¥30 关于#r语言#的问题:如何对R语言中mfgarch包中构建的garch-midas模型进行样本内长期波动率预测和样本外长期波动率预测
  • ¥15 ETLCloud 处理json多层级问题
  • ¥15 matlab中使用gurobi时报错
  • ¥15 这个主板怎么能扩出一两个sata口
  • ¥15 不是,这到底错哪儿了😭
  • ¥15 2020长安杯与连接网探