如何在 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
值?
您无法保证在没有同步的情况下观察到另一个 goroutine 中对变量值所做的更改。有关详细信息,请参阅 The Go Memory Model。
因此,如果您想在另一个 goroutine 中更改 ctx.Response.Status
,要保证此更改在调用方 goroutine 中可见,请使用同步。
有多个同步原语。您可以使用频道或 sync
包。
使用频道:
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 update)是一个很好的做法,这样如果启动的 goroutine 以某种意外的方式结束(例如运行时恐慌),调用者 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
值?
您无法保证在没有同步的情况下观察到另一个 goroutine 中对变量值所做的更改。有关详细信息,请参阅 The Go Memory Model。
因此,如果您想在另一个 goroutine 中更改 ctx.Response.Status
,要保证此更改在调用方 goroutine 中可见,请使用同步。
有多个同步原语。您可以使用频道或 sync
包。
使用频道:
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 update)是一个很好的做法,这样如果启动的 goroutine 以某种意外的方式结束(例如运行时恐慌),调用者 goroutine 将不会得到永远被封锁。请注意,在这种情况下,完成信号只会在匿名函数结束时发送(即执行延迟函数时)。