douzhe9075 2018-04-26 19:41
浏览 10
已采纳

为什么结果与标志“ -race”不符?

Why the result is not as expected with flag "-race" ? It expected the same result: 1000000 - with flag "-race" and without this

https://gist.github.com/romanitalian/f403ceb6e492eaf6ba953cf67d5a22ff

package main

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

//$ go run -race main_atomic.go
//954203
//
//$ go run main_atomic.go
//1000000

type atomicCounter struct {
    val int64
}

func (c *atomicCounter) Add(x int64) {
    atomic.AddInt64(&c.val, x)
    runtime.Gosched()
}

func (c *atomicCounter) Value() int64 {
    return atomic.LoadInt64(&c.val)
}

func main() {
    counter := atomicCounter{}

    for i := 0; i < 100; i++ {
        go func(no int) {
            for i := 0; i < 10000; i++ {
                counter.Add(1)
            }
        }(i)
    }

    time.Sleep(time.Second)
    fmt.Println(counter.Value())
}
  • 写回答

1条回答 默认 最新

  • dougu3988 2018-04-26 21:03
    关注

    The reason why the result is not the same is because time.Sleep(time.Second) does not guarantee that all of your goroutines are going to be executed in the timespan of one second. Even if you execute go run main.go, it's not guaranteed that you will get the same result every time. You can test this out if you put time.Milisecond instead of time.Second, you will see much more inconsistent results.

    Whatever value you put in the time.Sleep method, it does not guarantee that all of your goroutines will be executed, it just means that it's less likely that all of your goroutines won't finish in time.

    For consistent results, you would want to synchronise your goroutines a bit. You can use WaitGroup or channels.

    With WaitGroup:

    //rest of the code above is the same
    func main() {
        counter := atomicCounter{}
        var wg sync.WaitGroup
        for i := 0; i < 100; i++ {
            wg.Add(1)
            go func(no int) {
                for i := 0; i < 10000; i++ {
                    counter.Add(1)
                }
                wg.Done()
            }(i)
        }
    
        wg.Wait()
        fmt.Println(counter.Value())
    }
    

    With channels:

    func main() {
        valStream := make(chan int)
        doneStream := make(chan int)
        result := 0
        for i := 0; i < 100; i++ {
            go func() {
                for i := 0; i < 10000; i++ {
                    valStream <- 1
                }
                doneStream <- 1
            }()
        }
    
        go func() {
            counter := 0
            for count := range doneStream {
                counter += count
                if counter == 100 {
                    close(doneStream)
                }
            }
            close(valStream)
        }()
    
        for val := range valStream {
            result += val
        }
        fmt.Println(result)
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥20 基于MSP430f5529的MPU6050驱动,求出欧拉角
  • ¥20 Java-Oj-桌布的计算
  • ¥15 powerbuilder中的datawindow数据整合到新的DataWindow
  • ¥20 有人知道这种图怎么画吗?
  • ¥15 pyqt6如何引用qrc文件加载里面的的资源
  • ¥15 安卓JNI项目使用lua上的问题
  • ¥20 RL+GNN解决人员排班问题时梯度消失
  • ¥60 要数控稳压电源测试数据
  • ¥15 能帮我写下这个编程吗
  • ¥15 ikuai客户端l2tp协议链接报终止15信号和无法将p.p.p6转换为我的l2tp线路