如何在goroutine闭包内更改外部变量的值

时间:2015-08-13 08:36:15

标签: go concurrency closures 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值?

1 个答案:

答案 0 :(得分:2)

您无法保证在没有同步的情况下观察另一个goroutine 中变量值的更改。有关详细信息,请参阅The Go Memory Model

因此,如果您想在另一个goroutine中更改<ion-scroll direction="x" class="item row" id="galleryline1"> <div class="first_row" id="firstrow"> <div> <img ng-repeat="image in allimages" ng-src="{{image.src}}" ng-click="showImages(image.title)" class="image-list-thumb"/> </div> </div> </ion-scroll> ,则可以保证在调用者goroutine使用同步中可以看到此更改。

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

使用频道:

ctx.Response.Status

使用sync.WaitGroup

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.Mutex

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

注意:

优良作法是使用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 发出完成信号(在您的情况下为ctx更新),以便如果启动的goroutine以某种意外的方式结束(例如运行时恐慌),则调用者goroutine将不会永远被阻止。但请注意,在这种情况下,完成信号将仅在匿名函数结束时发送(即执行延迟函数时)。