Как реализуется многозадачность в Go

Ответ

В Go многозадачность (или, точнее, конкурентность) реализуется через горутины (goroutines) — легковесные потоки, управляемые рантаймом Go. Они работают поверх системных потоков, но потребляют значительно меньше ресурсов (стартовый стек ~2KB, динамически расширяемый).

Горутины запускаются с помощью ключевого слова go:

go func() {
    fmt.Println("Работаю в горутине")
}()

Планировщик Go (scheduler) эффективно распределяет горутины по доступным CPU-ядрам, используя модель M:N (M горутин на N системных потоков). Для безопасной синхронизации и обмена данными между горутинами используются каналы (channels) и примитивы из пакета sync (Mutex, RWMutex, WaitGroup, Cond и др.).

Пример использования sync.WaitGroup для ожидания завершения горутин:

package main

import (
    "fmt"
    "sync"
    "time"
)

func main() {
    var wg sync.WaitGroup

    wg.Add(1) // Увеличиваем счетчик на 1
    go func() {
        defer wg.Done() // Уменьшаем счетчик по завершении горутины
        fmt.Println("Горутина 1 начала работу")
        time.Sleep(time.Second) // Имитация работы
        fmt.Println("Горутина 1 завершила работу")
    }()

    wg.Add(1)
    go func() {
        defer wg.Done()
        fmt.Println("Горутина 2 начала работу")
        time.Sleep(500 * time.Millisecond)
        fmt.Println("Горутина 2 завершила работу")
    }()

    fmt.Println("Ожидаем завершения всех горутин...")
    wg.Wait() // Блокируемся до тех пор, пока счетчик не станет равен 0
    fmt.Println("Все горутины завершили работу.")
}

Главные преимущества такого подхода: простота использования, автоматическое масштабирование конкурентных задач и эффективное использование ресурсов системы, что делает Go отличным выбором для высоконагруженных сетевых сервисов.