使用 goroutines 时将函数调用包装到闭包中
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()
}
在这里测试:http://play.golang.org/p/nMlnTkbwVf
可以看到将 startWorker(i)
包装到 func() { startWorker(i) }()
会导致仅调用第 5 个 worker。
闭包从外部范围捕获变量的方式似乎有问题。为什么会这样?闭包是否使用按引用传递方式传递外部变量而不是按值传递?
这就是所有语言中闭包的工作方式,如果你想那样做,你必须隔离变量。
go func(i int) { startWorker(i) }(i)
在使用 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()
}
在这里测试:http://play.golang.org/p/nMlnTkbwVf
可以看到将 startWorker(i)
包装到 func() { startWorker(i) }()
会导致仅调用第 5 个 worker。
闭包从外部范围捕获变量的方式似乎有问题。为什么会这样?闭包是否使用按引用传递方式传递外部变量而不是按值传递?
这就是所有语言中闭包的工作方式,如果你想那样做,你必须隔离变量。
go func(i int) { startWorker(i) }(i)