← Назад к вопросам

Как происходит конкурентность?

2.0 Middle🔥 181 комментариев
#Конкурентность и горутины

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Конкурентность в Go

Конкурентность в Go реализована через модель легковесных потоков, известных как goroutine, и мощную систему управления параллельными операциями. Это фундаментальный принцип языка, отличающий его от многих других.

Goroutine: основа конкурентности

Goroutine — это функция или метод, выполняемый независимо от основной программы. Она не является потоком ОС, а представляет собой "легковесный поток", управляемый планировщиком Go.

package main

import (
    "fmt"
    "time"
)

func main() {
    // Запуск goroutine с ключевым словом 'go'
    go func() {
        fmt.Println("Это выполняется в goroutine")
    }()
    
    fmt.Println("Это выполняется в main goroutine")
    time.Sleep(time.Millisecond * 100) // Даем время goroutine завершиться
}

Основные характеристики goroutine:

  • Создаются с ключевым словом go перед вызовом функции
  • Используют значительно меньше памяти чем традиционные потоки ОС (начальный размер ~2KB)
  • Создаются и управляются планировщиком Go, а не ОС
  • Могут выполняться на одном или нескольких ядрах CPU

Модель планирования: M, P, G

Внутренняя архитектура конкурентности Go построена на трех компонентах:

  • G (Goroutine) — объект goroutine, содержит информацию о стеке и состоянии
  • M (Machine) — поток ОС, который выполняет goroutines
  • P (Processor) — контекст планировщика, связывает M и G

Планировщик Go использует кооперативную многозадачность с прерыванием на определенных точках (вызовы функций, блокировка каналов, системные вызовы). Это позволяет избежать сложной синхронизации и снижает нагрузку.

Синхронизация и коммуникация через каналы

Конкурентность требует безопасной синхронизации. В Go это реализуется преимущественно через каналы (channels):

package main

import (
    "fmt"
)

func worker(id int, jobs <-chan int, results chan<- int) {
    for job := range jobs {
        fmt.Printf("Worker %d processing job %d\n", id, job)
        results <- job * 2
    }
}

func main() {
    jobs := make(chan int, 5)
    results := make(chan int, 5)
    
    // Запускаем три goroutine-работника
    for w := 1; w <= 3; w++ {
        go worker(w, jobs, results)
    }
    
    // Отправляем задачи
    for j := 1; j <= 5; j++ {
        jobs <- j
    }
    close(jobs)
    
    // Получаем результаты
    for i := 1; i <= 5; i++ {
        fmt.Println("Result:", <-results)
    }
}

Каналы обеспечивают:

  • Синхронизацию между goroutines
  • Безопасную передачу данных без явных мьютексов
  • Блокирующие и неблокирующие операции через select

Дополнительные механизмы синхронизации

Для более сложных случаев Go предоставляет традиционные инструменты в пакете sync:

package main

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

var (
    counter int
    mutex   sync.Mutex
)

func increment() {
    mutex.Lock()
    counter++
    mutex.Unlock()
}

func main() {
    var wg sync.WaitGroup
    
    for i := 0; i < 100; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            increment()
        }()
    }
    
    wg.Wait()
    fmt.Println("Final counter:", counter)
}

Включает:

  • Mutex и RWMutex для защиты общих данных
  • WaitGroup для ожидания завершения goroutines
  • Atomic операции через sync/atomic для низкоуровневой синхронизации

Особенности и преимущества конкурентности в Go

  1. Простая модель программирования — конкурентность становится частью дизайна программы
  2. Эффективное использование ресурсов — тысячи goroutines могут работать в одном процессе
  3. Чистая коммуникация через каналы — философия "Do not communicate by sharing memory; share memory by communicating"
  4. Встроенная поддержка — не требует внешних библиотек или сложной конфигурации

Конкурентность в Go — это не просто техническая особенность, а основной принцип дизайна языка, позволяющий создавать высокопроизводительные системы с относительно простым и безопасным кодом.