Ответ
В Go управление конкурентностью реализовано через горутины (goroutines) и каналы, а не через прямое управление системными потоками (тредами). Модель, которую использует Go, называется M:N планированием.
Это означает, что M горутин выполняются поверх N системных потоков. Обычно N равно количеству доступных ядер процессора (GOMAXPROCS
).
Ключевые компоненты планировщика Go (GMP model):
- G (Goroutine): Легковесный поток выполнения. Имеет свой небольшой стек (~2 КБ), который может расти и сжиматься. Создание горутины намного дешевле создания системного потока.
- M (Machine): Системный поток (OS thread), управляемый операционной системой.
- P (Processor): Контекст для выполнения Go-кода. У каждого P есть локальная очередь готовых к выполнению горутин. Количество P по умолчанию равно
runtime.NumCPU()
.
Как это работает:
Планировщик Go распределяет горутины (G) по процессорам (P). Системный поток (M) "берёт" себе P и начинает выполнять горутины из его очереди. Если горутина блокируется (например, на системном вызове или ожидании данных из канала), M отсоединяется от P, а планировщик может прикрепить к этому P другой M (или создать новый), чтобы продолжить выполнение других горутин из очереди. Это позволяет эффективно утилизировать процессорные ядра, не блокируя потоки.
Пример с Worker Pool:
// worker — горутина, которая обрабатывает задачи из канала jobs
func worker(id int, jobs <-chan int, results chan<- int) {
for j := range jobs {
// какая-то работа
results <- j * 2
}
}
func main() {
jobs := make(chan int, 100)
results := make(chan int, 100)
// Запуск 3 горутин-воркеров
for w := 1; w <= 3; w++ {
go worker(w, jobs, results)
}
// Отправка 5 задач в канал
for j := 1; j <= 5; j++ {
jobs <- j
}
close(jobs) // Закрываем канал, чтобы воркеры завершились
// Сбор результатов
for r := 1; r <= 5; r++ {
<-results
}
}
Синхронизация: Для координации горутин используются каналы (идиоматический способ) и примитивы из пакета sync
, такие как sync.Mutex
для защиты общих данных и sync.WaitGroup
для ожидания завершения группы горутин.