使用 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)