Запуск функции без ожидания
Ключевое слово go начинает вызов функции в отдельной горутине. Вызывающая функция продолжает работу, а сама горутина выполняется независимо. Конструкция работает также с анонимной функцией, то есть замыканием.
Обычный вызов функции дожидается её результата. Запуск через go не возвращает результат вызывающему коду, поэтому для обмена данными нужны канал, защищённое общее состояние или другая координация. Если main завершится, процесс тоже завершится: он не ждёт оставшиеся горутины автоматически.
Замыкание может обращаться к переменным внешней функции. Когда каждой задаче нужны собственные значения, передай их параметрами функции-горутины: так входные данные вызова видны явно и не зависят от того, как меняется внешнее состояние.
Пример
package main
import (
"fmt"
"sync"
)
type reply struct {
position int
message string
}
func main() {
names := []string{"Ася", "Борис", "Вера"}
replies := make(chan reply, len(names))
var workers sync.WaitGroup
for position, name := range names {
workers.Add(1)
go func(position int, name string) {
defer workers.Done()
replies <- reply{position: position, message: "готово: " + name}
}(position, name)
}
go func() {
workers.Wait()
close(replies)
}()
ordered := make([]string, len(names))
for reply := range replies {
ordered[reply.position] = reply.message
}
for _, message := range ordered {
fmt.Println(message)
}
}
Основная функция передаёт позиции и имена в параметры каждой горутины. Канал достаточно вместителен для всех ответов, а после завершения отправителей координатор закрывает его. Основная функция читает до закрытия и сохраняет ответы по исходному индексу, поэтому завершение в любом порядке не меняет печать.
Передача параметров — ясный способ зафиксировать значения для конкретного вызова. Если вместо этого менять общую переменную из нескольких горутин, нужен mutex или передача сообщений через канал; иначе возникает гонка данных.