Ответ
Горутина — это легковесная, управляемая средой выполнения (runtime) Go, функция или метод, выполняющийся конкурентно с другими горутинами. Это ключевая концепция для достижения конкурентности в Go.
Ключевые отличия от системных потоков:
Стоимость создания и память:
- Горутины: Очень дешевы. Начальный размер стека всего ~2 КБ, который может динамически расти и сжиматься. Можно легко запустить сотни тысяч и даже миллионы горутин.
- Потоки ОС: Дорогие. Имеют фиксированный и значительно больший размер стека (обычно 1-8 МБ). Создание большого количества потоков сильно нагружает ОС.
Управление и переключение контекста:
- Горутины: Управляются планировщиком Go в пространстве пользователя (user space). Переключение между горутинами происходит очень быстро и не требует дорогостоящих системных вызовов.
- Потоки ОС: Управляются ядром операционной системы. Переключение контекста между потоками — медленная операция.
Модель выполнения (M:N):
- Планировщик Go распределяет M горутин для выполнения на N системных потоках (где M обычно гораздо больше N). Это позволяет эффективно утилизировать процессорные ядра.
Идиоматичный пример с sync.WaitGroup
:
Использование time.Sleep
для синхронизации — плохая практика. Правильнее использовать примитивы синхронизации, например sync.WaitGroup
.
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var wg sync.WaitGroup
wg.Add(1) // Сообщаем, что нужно дождаться одну горутину
go func() {
defer wg.Done() // Сигнализируем о завершении работы в конце функции
fmt.Println("Горутина работает!")
time.Sleep(time.Second)
}()
fmt.Println("Основная функция ждет завершения горутины...")
wg.Wait() // Блокируем выполнение, пока счетчик WaitGroup не станет равен 0
fmt.Println("Горутина завершила работу.")
}