Перейти до основного вмісту
Модуль 7 · Урок 1 із 531/50 у курсі~12 min
Модульні уроки (1/5)

Goroutines: легкий паралелізм

goroutine — це одиниця одночасного виконання, якою керує Go час виконання. Ви запускаєте його з ключовим словом go перед функцією дзвонити:

Go
go greet("Anna")         // chiamata a funzione esistente
go func() {              // funzione anonima
    fmt.Println("hi")
}()

Інструкція go повертає негайно: горутина починається в паралельно, і абонент продовжує йти.

Чому вони «легкі»

  • Початковий стек ~2 КБ (динамічно зростає, за потреби до сотень МБ).
  • Мультиплексований на невелику кількість потоків ОС під час виконання (GOMAXPROCS).
  • Тисячі/мільйони goroutines є рутиною; з потоками ОС вони були б неможливі.

Концептуально це «одночасний вогонь і забув», але з усім ідіоматичні інструменти для координації (канали, sync.WaitGroup, context).

головне не чекає

Go
func main() {
    go func() { fmt.Println("ciao dalla goroutine") }()
    // main esce subito: niente garanzia che la goroutine completi
}

Коли main повертається, процес завершується: горутини не отримують щоб «закінчити свою роботу», їх просто вбивають разом із процес. Потрібна явна синхронізація.

Синхронізація: попередній перегляд

Три інструменти, які ви побачите в наступних уроках:

Go
// 1) Channel: la goroutine "segnala" via canale
done := make(chan struct{})
go func() {
    work()
    done <- struct{}{}
}()
<-done   // attendi

// 2) sync.WaitGroup: N goroutine
var wg sync.WaitGroup
wg.Add(1)
go func() { defer wg.Done(); work() }()
wg.Wait()

// 3) context: cancellazione/timeout propagati

«Класична» помилка замикання в циклі

До Go 1.21 це було частою проблемою:

Go
for i := 0; i < 3; i++ {
    go func() { fmt.Println(i) }()  // stampa "3 3 3" su versioni vecchie
}

З Go 1.22 змінна for свіжо створюється на кожному ітерації, тому помилку виправлено за замовчуванням. У старих кодових базах ви це зробите все ще бачите шаблон виправлення:

Go
for i := 0; i < 3; i++ {
    i := i           // shadow esplicito
    go func() { fmt.Println(i) }()
}
// oppure passa come argomento:
for i := 0; i < 3; i++ {
    go func(n int) { fmt.Println(n) }(i)
}

Goroutine != Потік ОС

АспектGoroutineПотік ОС
Початковий стек~2 КБ1–8 МБ (виділено на початку)
Створеннянаносекундмікросекунд
ПлануванняGo runtime (кооператив)ядро (превентивне)
Практичний підрахунок100 тисяч+кілька тисяч

Один потік ОС може розміщувати багато gor-програм. Час виконання рухається goroutines через потоки, коли це необхідно.

Спробуйте

вправи#go.m7.l1.e1
Спроби: 0Завантаження…

Запустіть функцію привітання як goroutine та зачекайте 100 мс із часом. Перейдіть у режим сну перед виходом з основного.

Завантаження редактора…
Показати підказку

`go` перед викликом функції запускає gor-програму.

Рішення доступне після 3 спроб

вправи#go.m7.l1.e2
Спроби: 0Завантаження…

Запустіть анонімну функцію як goroutine, яка друкує «привіт».

Завантаження редактора…
Показати підказку

Анонімна функція викликається з `()` в кінці: `go func(){...}()`.

Рішення доступне після 3 спроб

Quiz#go.m7.l1.e3
Готовий

Що трапиться, якщо `main` завершить роботу до того, як горутина завершиться?

Go
func main() {
  go work()
  // main ritorna immediatamente
}
Варіанти відповідей

Підведення підсумків

  • go f() запускає f() одночасно; воно повертається негайно.
  • Goroutine = початковий ~2 КБ, мультиплексований на кілька потоків ОС.
  • main не чекає: потрібна синхронізація (канал/WaitGroup/контекст).
  • time.Sleep лише дидактичний, а не для синхронізації у виробництві. — Починаючи з версії Go 1.22, змінна for стає «свіжою» на кожній ітерації (більше немає помилки «3 3 3»).