登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  Golang >  Go问答

Go 内存模型:使用正确的同步方式分配值给字段

来源:stackoverflow

时间:2024-02-14 16:36:24 273浏览 收藏

各位小伙伴们,大家好呀!看看今天我又给各位带来了什么文章?本文标题是《Go 内存模型:使用正确的同步方式分配值给字段》,很明显是关于Golang的文章哈哈哈,其中内容主要会涉及到等等,如果能帮到你,觉得很不错的话,欢迎各位多多点评和分享!

问题内容

下面是我在 go 中实现 promise 的核心部分。

// a promise represents the future result of a call to a function.
type promise struct {
    // state is the current state of this promise.
    state int32
    // done is closed when execution completes to unblock concurrent waiters.
    done chan struct{}
    // the function that will be used to populate the outcome.
    function function
    // outcome is set when execution completes.
    outcome outcome
}

// get returns the value associated with a promise.
//
// all calls to promise.get on a given promise return the same result
// but the function is called (to completion) at most once.
//
// - if the underlying function has not been invoked, it will be.
// - if ctx is cancelled, get returns (nil, context.canceled).
func (p *promise) get(ctx context.context) outcome {
    if ctx.err() != nil {
        return outcome{
            value: nil,
            err:   ctx.err(),
        }
    }

    if p.changestate(iscreated, isexecuted) {
        return p.run(ctx)
    }

    return p.wait(ctx)
}

// run starts p.function and returns the result.
func (p *promise) run(ctx context.context) outcome {
    go func() {
        v, err := doexecute(ctx, p.function)

        p.outcome = outcome{
            value: v,
            err:   err,
        }
        p.function = nil // aid gc
        close(p.done)
    }()

    return p.wait(ctx)
}

// wait waits for the value to be computed, or ctx to be cancelled.
func (p *promise) wait(ctx context.context) outcome {
    select {
    case <-p.done:
        return p.outcome

    case <-ctx.done():
        return outcome{
            value: nil,
            err:   ctx.err(),
        }
    }
}

func (p *promise) changestate(from, to state) bool {
    return atomic.compareandswapint32(&p.state, int32(from), int32(to))
}

一位同事今天给了我一个 go 内存模型文章的链接。在文章中,作者提供了以下示例,并提到 g 可以打印 2,然后打印 0。

var a, b int

func f() {
    a = 1
    b = 2
}

func g() {
    print(b)
    print(a)
}

func main() {
    go f()
    g()
}

存在竞争的程序是不正确的,并且可能表现出非顺序一致的执行。特别要注意的是,读 r 可能会观察到与 r 并发执行的任何写 w 写入的值。即使发生这种情况,也不意味着在 r 之后发生的读取会观察到在 w 之前发生的写入。

到目前为止,我一直认为在关闭 done 通道之前设置一个变量可以保证其他例程能够看到该变量的最新值。

但是,上面的示例让我质疑我对 go 工作原理的理解以及使用 done 通道是否会产生任何差异。其他例程是否可以检测到 done 通道已关闭并继续读取尚未更新的字段?

如果您能向我解释我的信念是否仍然正确,我将不胜感激。如果错误,请告诉我同步字段读写的正确方法。


正确答案


对 p.outcome 的赋值是“在”close(done) 之前排序的,因此任何检测到 done 关闭的 goroutine 将看到 p.outcome 的最新值,因为如果 done 关闭,则 p.outcomez qbendczqb 之前发生过它。

p.changestate 可能有一场比赛,但您没有将其包含在您的帖子中。

也就是说,通道和 goroutine 提供了与 promise 相同的功能,并且以更简洁的方式实现:

resultCh:=make(chan resultType)
go func() {
   resultCh<-someFunc(ctx)
}()

select {
   case <-ctx.Done():
     // Canceled
   case result:=<-resultCh:
     // result is ready
}

终于介绍完啦!小伙伴们,这篇关于《Go 内存模型:使用正确的同步方式分配值给字段》的介绍应该让你收获多多了吧!欢迎大家收藏或分享给更多需要学习的朋友吧~golang学习网公众号也会发布Golang相关知识,快来关注吧!

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