将函数调用包装到闭包中时使用goroutine。

huangapple go评论80阅读模式
英文:

Wrapping a function call into a closure when using goroutines

问题

将函数调用包装到闭包中,在使用goroutine时会导致意外的行为。

考虑以下示例:

package main

import (
    "log"
    "sync"
    "time"
)

var workerNum = 5
var wg sync.WaitGroup

func block() {
    dur := 300 * time.Millisecond
    //time.Sleep()
    select {
    case <- time.After(dur): {}
    }
}

func startWorker(worker int) {
    for i:=0; i < 3; i++{
        log.Printf("Worker %d woke up! \n", worker)
        block()
    }
    wg.Done()
}

func main() {
    for i:=0; i < workerNum; i++ {
        //go func() { startWorker(i) }()
        go startWorker(i)
    }

    wg.Add(workerNum)
    wg.Wait()
}

在这个示例中,可以看到将startWorker(i)包装到func() { startWorker(i) }()中只调用了第5个worker。

看起来闭包从外部作用域捕获变量的方式有问题。为什么会发生这种情况?闭包是否使用引用传递而不是值传递的方式传递外部变量?

英文:

Wrapping a function call into a closure leads to an unexpected behaviour when using goroutines.

Consider the following example:

package main

import (
    &quot;log&quot;
    &quot;sync&quot;
    &quot;time&quot;
)

var workerNum = 5
var wg sync.WaitGroup

func block() {
    dur := 300 * time.Millisecond
    //time.Sleep()
    select {
    case &lt;- time.After(dur): {}
    }
}

func startWorker(worker int) {
    for i:=0; i &lt; 3; i++{
        log.Printf(&quot;Worker %d woke up! \n&quot;, worker)
        block()
    }
    wg.Done()
}

func main() {
    for i:=0; i &lt; workerNum; i++ {
        //go func() { startWorker(i) }()
        go startWorker(i)
    }

    wg.Add(workerNum)
    wg.Wait()
}

Test it here: http://play.golang.org/p/nMlnTkbwVf

One can see that wrapping startWorker(i) into func() { startWorker(i) }() results in calling only the 5-th worker.

It looks like there is something wrong in the way how closures capture variables from the outer scope. Why is this happening? Do closures use pass-by-reference way for passing outer variables instead of pass-by-value?

答案1

得分: 2

这是所有语言中闭包的工作方式,如果你想以这种方式做,你必须隔离变量。

go func(i int) { startWorker(i) }(i)
英文:

That's how closures in all languages work, if you want to do it that way, you have to isolate the variable.

go func(i int) { startWorker(i) }(i)

huangapple
  • 本文由 发表于 2015年6月1日 05:49:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/30563064.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定