sync.waitGroup 的协程每次输出不同的值

Goroutine with sync.waitGroup output different value each time

下面的代码每次执行后都会打印不同的值,但我希望这些值相同,如何在不使用 time.Sleep

的情况下更改下面的代码
package main

import (
    "fmt"
    "sync"
)

var total int
var wg sync.WaitGroup

// Inc increments the counter for the given key.
func inc(num int) {
    total += num
    wg.Done()
}

// Value returns the current value of the counter for the given key.
func getValue() int {
    return total
}

func main() {
    for i := 1; i <= 1000; i++ {
        wg.Add(1)
        go inc(i)
    }
    wg.Wait()
    fmt.Println(getValue())
}

您每次获得不同值的原因是 total += num 中的竞争条件。

一个简单的修复方法是添加互斥锁: var mu sync.Mutex

并在inc 中使用它:

func inc(num int) {
    mu.Lock()
    defer mu.Unlock()
    total += num
    wg.Done()
}

您有一场数据竞赛,结果未定。您必须同步对共享变量的访问:

var total int
var lock sync.Mutex
var wg sync.WaitGroup

// Inc increments the counter for the given key.
func inc(num int) {
    lock.Lock()
    defer lock.Unlock()
    total += num
    wg.Done()
}

// Value returns the current value of the counter for the given key.
func getValue() int {
    lock.Lock()
    defer lock.Unlock()
    return total
}

或者,使用 sync/atomic 到 access/modify 变量。

已经提到您有“数据竞争”,使用 Mutex 是一个解决方案。或者你可以使用 atomic 包,它更快。

package main

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

var total uint64
var wg sync.WaitGroup

func inc(num uint64) {
    atomic.AddUint64(&total, 1)
    wg.Done()
}

// Value returns the current value of the counter for the given key.
func getValue() uint64 {
    return atomic.LoadUint64(&total)
}

func main() {
    for i := uint64(1); i <= 1000; i++ {
        wg.Add(1)
        go inc(i)
    }
    wg.Wait()
    fmt.Println(getValue())
}