sync.WaitGroup在我的预期中表现不如我所期望的,我在这里漏掉了什么?

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

sync.WaitGroup not behaving as I expect, what am I missing here?

问题

给定以下代码:

package main

import (
	"fmt"
	"sync"
)

func main() {
	n := 100

	var wg sync.WaitGroup
	wg.Add(n)

	x := 0
	for i := 0; i < n; i++ {
		go func() {
			defer wg.Done()
			x++
		}()
	}

	wg.Wait()
	fmt.Println(n, x)
}

我期望在最后打印出来之前,x 的值总是达到 100,但有时它的值会低至 95。我在这里漏掉了什么?

英文:

Given the following:

<!-- language: lang-go -->

package main

import (
    &quot;fmt&quot;
    &quot;sync&quot;
)

func main() {
    n := 100

    var wg sync.WaitGroup
    wg.Add(n)

    x := 0
    for i := 0; i &lt; n; i++ {
	    go func() {
		    defer wg.Done()
		    x++
	    }()
    }

    wg.Wait()
    fmt.Println(n, x)
}

I would expect x to always reach 100 by the time it prints at the end, but it sometimes prints as low as 95. What am I missing here?

答案1

得分: 5

x上有一个竞争条件。一种修复方法是使用互斥锁保护x

var mu sync.Mutex
var wg sync.WaitGroup
wg.Add(n)

x := 0
for i := 0; i < n; i++ {
    go func() {
        defer wg.Done()
        mu.Lock()
        x++
        mu.Unlock()
    }()
}

wg.Wait()
fmt.Println(n, x)

playground示例

我建议在发现Go程序中有多个goroutine时,如果遇到令人困惑的情况,可以运行竞争检测器

英文:

There's a race on x. One fix is to protect x with a mutex:

var mu sync.Mutex
var wg sync.WaitGroup
wg.Add(n)

x := 0
for i := 0; i &lt; n; i++ {
    go func() {
        defer wg.Done()
        mu.Lock()
        x++
        mu.Unlock()
    }()
}

wg.Wait()
fmt.Println(n, x)

playground example

I suggest running the race detector whenever one finds something puzzling in a Go program with more than one goroutine.

答案2

得分: 1

使用sync.atomic方法以原子方式访问x。

package main

import (
    "fmt"
    "sync"
    "sync/atomic"
)

func main() {
    n := 100

    var wg sync.WaitGroup
    wg.Add(n)

    var x int32
    for i := 0; i < n; i++ {
        go func() {
            defer wg.Done()
            atomic.AddInt32(&x, 1)
        }()
    }

    wg.Wait()
    fmt.Println(n, x)
}

使用sync.atomic的AddInt32方法可以以原子方式增加x的值。在循环中的每个goroutine中,我们使用atomic.AddInt32来递增x的值。通过使用原子操作,我们可以确保多个goroutine同时访问和修改x时不会发生竞争条件。最后,我们使用fmt.Println打印出n和x的值。

英文:

use sync.atomic method to access x atomically.

package main

import (
    &quot;fmt&quot;
    &quot;sync&quot;
    &quot;sync/atomic&quot;
)

func main() {
    n := 100

    var wg sync.WaitGroup
    wg.Add(n)

    var x int32
    for i := 0; i &lt; n; i++ {
        go func() {
            defer wg.Done()
            atomic.AddInt32(&amp;x, 1)
        }()
    }

    wg.Wait()
    fmt.Println(n, x)
}

huangapple
  • 本文由 发表于 2015年9月27日 07:22:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/32803018.html
匿名

发表评论

匿名网友

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

确定