英文:
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 (
"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()
}
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)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论