登录
首页 >  Golang >  Go问答

为什么 goroutine 无法读取全局 var ops 值?

来源:stackoverflow

时间:2024-04-22 17:33:39 273浏览 收藏

偷偷努力,悄无声息地变强,然后惊艳所有人!哈哈,小伙伴们又来学习啦~今天我将给大家介绍《为什么 goroutine 无法读取全局 var ops 值?》,这篇文章主要会讲到等等知识点,不知道大家对其都有多少了解,下面我们就一起来看一吧!当然,非常希望大家能多多评论,给出合理的建议,我们一起学习,一起进步!

问题内容

package main

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

func init() {
    runtime.GOMAXPROCS(runtime.NumCPU())
}

func main() {
    var t1 = time.Now()
    var ops uint64 = 0
    go func() {
        for {
            time.Sleep(time.Second)
            opsFinal := atomic.LoadUint64(&ops)
            fmt.Println("ops:", opsFinal, "qps:", opsFinal/uint64(time.Since(t1).Seconds()))
        }
    }()

    for {
        atomic.AddUint64(&ops, 1)
        //runtime.Gosched()
    }
}

在这种情况下,每秒都会输出“ops: 0 qps: 0”,为什么无法读取 goroutine 中的 ops?

但是当添加runtime.gosched()时,一切正常!

每个人都可以帮助我吗?


解决方案


我对 The Go Memory Model 的理解是,这是您编写的程序的正确执行:没有任何东西可以保证主程序中的 adduint64() 调用发生在 loaduint64() 调用之前在 goroutine 中,因此在任何写入发生之前发生变量的每次读取都是合法的。如果编译器知道 "sync/atomic" 是特殊的,并得出结论增量的结果是不可观察的,因此只需删除最后一个循环,我就不会感到完全震惊。

The Go Memory Modelsync/atomic documentation 都建议不要使用您正在使用的方法。 "sync/atomic" 告诫:

通过通信共享内存;不要通过共享内存进行通信。

更好的程序可能如下所示:

package main

import "fmt"
import "time"

func count(op <-chan struct{}) {
    t1 := time.now()
    ops := 0
    tick := time.tick(time.second)
    for {
        select {
        case <-op:
            ops++
        case <-tick:
            dt := time.since(t1).seconds()
            fmt.printf("ops: %d qps: %f\n", ops, float64(ops)/dt)
        }
    }
}

func main() {
    op := make(chan struct{})
    go count(op)
    for {
        op <- struct{}{}
    }
}

请注意,除了通过通道发送的数据之外,主程序和 goroutine 之间不共享任何状态。

我会更新 go 版本,请检查,

[mh-cbon@pc3 y] $ go run main.go 
ops: 97465383 qps: 97465383
ops: 195722110 qps: 97861055
ops: 293058057 qps: 97686019
ops: 390971243 qps: 97742810
^Csignal: interrupt
[mh-cbon@pc3 y] $ go version
go version go1.10 linux/amd64
[mh-cbon@pc3 y] $ gvm use 1.8
Now using version go1.8
[mh-cbon@pc3 y] $ go version
go version go1.8 linux/amd64
[mh-cbon@pc3 y] $ go run main.go 
ops: 0 qps: 0
ops: 0 qps: 0
^Csignal: interrupt
[mh-cbon@pc3 y] $

本篇关于《为什么 goroutine 无法读取全局 var ops 值?》的介绍就到此结束啦,但是学无止境,想要了解学习更多关于Golang的相关知识,请关注golang学习网公众号!

声明:本文转载于:stackoverflow 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>