Обертывание вызова функции в замыкание при использовании горутин

Оборачивание вызова функции в замыкание приводит к неожиданному поведению при использовании горутин.

Рассмотрим следующий пример:

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-го воркера.

Похоже, что-то не так в том, как замыкания захватывают переменные из внешней области видимости. Почему это происходит? Используют ли замыкания способ передачи по ссылке для передачи внешних переменных вместо передачи по значению?


person Max Malysh    schedule 31.05.2015    source источник


Ответы (1)


Вот как работают замыкания во всех языках, если вы хотите сделать это таким образом, вы должны изолировать переменную.

go func(i int) { startWorker(i) }(i)
person OneOfOne    schedule 31.05.2015