Горутины
Горутина — это функция, выполняющаяся конкурентно с другими горутинами в том же адресном пространстве. Горутины гораздо легче потоков ОС: начальный стек занимает всего несколько килобайт, а планировщик Go распределяет тысячи горутин по небольшому числу системных потоков.
Запуск горутины
Достаточно поставить ключевое слово go перед вызовом функции:
package main
import (
"fmt"
"time"
)
func say(s string) {
for i := 0; i < 3; i++ {
fmt.Println(s, i)
time.Sleep(100 * time.Millisecond)
}
}
func main() {
go say("горутина")
say("main")
}
Когда функция main завершается, программа заканчивает работу,
не дожидаясь остальных горутин. Поэтому для ожидания используют
каналы или sync.WaitGroup,
а не time.Sleep.
Анонимные функции
for i := 0; i < 3; i++ {
go func(n int) {
fmt.Println("работник", n)
}(i)
}
Начиная с Go 1.22 переменная цикла создаётся заново на каждой итерации,
поэтому замыкание go func() { fmt.Println(i) }() тоже работает корректно.
Модель G-M-P
- G (goroutine) — горутина;
- M (machine) — системный поток;
- P (processor) — логический процессор с очередью горутин.
Их количество задаёт
GOMAXPROCS(по умолчанию — число ядер).
Советы
- Всегда понимайте, когда и как горутина завершится — иначе будет утечка.
- Для отмены долгих операций используйте
context.Context. - Запускайте тесты с флагом
-race, чтобы находить гонки данных.