如何在goroutine闭包内更改外部变量的值 [英] How to change external variable's value inside a goroutine closure
问题描述
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屋!