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)
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥50 汇编语言除法溢出问题
  • ¥50 C++实现删除N个数据列表共有的元素
  • ¥15 Visual Studio问题
  • ¥15 state显示变量是字符串形式,但是仍然红色,无法引用,并显示类型不匹配
  • ¥20 求一个html代码,有偿
  • ¥100 关于使用MATLAB中copularnd函数的问题
  • ¥20 在虚拟机的pycharm上
  • ¥15 jupyterthemes 设置完毕后没有效果
  • ¥15 matlab图像高斯低通滤波
  • ¥15 针对曲面部件的制孔路径规划,大家有什么思路吗