Что такое многопоточность и как модель конкурентности реализована в Go?

Ответ

Многопоточность (Multithreading) — это способность операционной системы или приложения выполнять несколько потоков (threads) одновременно в рамках одного процесса. Потоки разделяют общее адресное пространство (память), что упрощает обмен данными, но создает риск возникновения гонок данных (race conditions), требуя механизмов синхронизации (мьютексы, семафоры).

Реализация в Go

В Go используется иная, более высокоуровневая модель конкурентности, основанная на горутинах (goroutines) и каналах (channels).


  • Горутины — это легковесные потоки, управляемые не ядром ОС, а средой выполнения (runtime) Go. Они требуют гораздо меньше памяти (несколько КБ) по сравнению с системными потоками (МБ), что позволяет создавать сотни тысяч и даже миллионы горутин одновременно.



  • Каналы — это типизированные конвейеры, через которые можно безопасно передавать данные между горутинами. Они обеспечивают синхронизацию и предотвращают гонки данных, следуя принципу: "Не обменивайтесь данными через общую память; обменивайтесь памятью через каналы".


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

Вместо time.Sleep(), который является ненадежным способом ожидания, используется sync.WaitGroup для гарантированного завершения всех горутин.

package main

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

func worker(id int, wg *sync.WaitGroup) {
    defer wg.Done() // Уменьшаем счетчик WaitGroup при завершении функции

    fmt.Printf("Worker %d startingn", id)
    time.Sleep(time.Second) // Имитация работы
    fmt.Printf("Worker %d donen", id)
}

func main() {
    var wg sync.WaitGroup // Создаем WaitGroup

    for i := 1; i <= 3; i++ {
        wg.Add(1) // Увеличиваем счетчик на 1 для каждой горутины
        go worker(i, &wg)
    }

    // Ожидаем, пока счетчик WaitGroup не станет равен 0
    wg.Wait()

    fmt.Println("All workers have finished")
}

Ключевые отличия от классических потоков:

  1. Легковесность: Горутины занимают значительно меньше ресурсов.
  2. Управление рантаймом: Планировщик Go эффективно распределяет горутины по системным потокам.
  3. Безопасная коммуникация: Каналы предоставляют встроенный механизм для синхронизации и обмена данными.