如何在goroutine闭包内更改外部变量的值 [英] How to change external variable's value inside a goroutine closure

查看:101
本文介绍了如何在goroutine闭包内更改外部变量的值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

func (this *l) PostUpload(ctx *Context) {

    //ctx.Response.Status = 500

    l, err := models.NewL(this.Config)
    go func() {
        err = l.Save(file) 
        if err != nil {
            ctx.Response.Status = 500
            ctx.Response.Body = err
        } else {
            ctx.Response.Status = 204
        }
    }()
}

如何在goroutine闭包内更改 ctx.Response.Status 值?

How to change ctx.Response.Status value inside the goroutine closure?

推荐答案

您不能保证在不同步的情况下观察另一个goroutine 中变量值的更改.有关详细信息,请参见 Go内存模型.

You have no guarantee to observe changes made to the value of a variable in another goroutine without synchronization. See The Go Memory Model for details.

因此,如果您想在另一个goroutine中更改 ctx.Response.Status ,请务必使用同步来确保此更改在调用方goroutine中可见.

So if you want to change ctx.Response.Status in another goroutine, for this change to be guaranteed to be visible in the caller goroutine use synchronization.

有多个同步原语.您可以使用频道或 sync 包.

There are multiple synchronization primitives. You can use channels or the sync package.

ch := make(chan int)

go func() {
    err = l.Save(file) 
    if err != nil {
        ctx.Response.Status = 500
        ctx.Response.Body = err
    } else {
        ctx.Response.Status = 204
    }
    ch <- 0 // Signal that ctx is updated
    // goroutine may do other works (not related to changing ctx)
}()

<- ch // Wait for the goroutine to finish updating ctx

使用 sync.WaitGroup :

var wg sync.WaitGroup
wg.Add(1)

go func() {
    err = l.Save(file) 
    if err != nil {
        ctx.Response.Status = 500
        ctx.Response.Body = err
    } else {
        ctx.Response.Status = 204
    }
    wg.Done() // Signal that ctx is updated
    // goroutine may do other works (not related to changing ctx)
}()

wg.Wait() // Wait for the goroutine to finish updating ctx

使用 sync.Mutex :

m := sync.Mutex{}
m.Lock()

go func() {
    err = l.Save(file) 
    if err != nil {
        ctx.Response.Status = 500
        ctx.Response.Body = err
    } else {
        ctx.Response.Status = 204
    }
    m.Unlock() // Signal that ctx is updated
    // goroutine may do other works (not related to changing ctx)
}()

m.Lock() // Wait for the goroutine to finish updating ctx

注意:

优良作法是使用 defer 通知完成(您的情况下为ctx更新),以便如果启动的goroutine以某种意外的方式结束(例如,运行时恐慌),则调用方goroutine不会永远被封锁.请注意,但是在这种情况下,完成信号将仅在匿名函数的末尾(即执行延迟函数时)发送.

It is good practice to signal the completion (ctx update in your case) using defer so that if the started goroutine would end in some unexpected way (e.g. runtime panic), the caller goroutine would not get blocked forever. Note that however in this case the completion signal will only be sent at the end of the anonymous function (that's when deferred functions are executed).

这篇关于如何在goroutine闭包内更改外部变量的值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆