如何在 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 将不会得到永远被封锁。请注意,在这种情况下,完成信号只会在匿名函数结束时发送(即执行延迟函数时)。