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

Что такое поток?

1.0 Junior🔥 221 комментариев
#Конкурентность и горутины#Операционные системы и Linux

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

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

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

Что такое поток (thread) в Go?

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

Отличие потоков ОС от горутин в Go

  • Поток ОС (OS thread): Управляется ядром ОС, имеет собственный стек (обычно 1-8 МБ), контекст выполнения и планируется системным планировщиком. Создание и переключение потоков — дорогие операции.
  • Горутина (goroutine): Легковесная сущность в Go, управляемая рантаймом. Имеет стек (от 2 КБ, динамически растет), работает поверх потоков ОС и планируется планировщиком Go.

Как Go использует потоки

Рантайм Go создает пул потоков ОС (обычно количество равно числу ядер CPU). На этих потоках планировщик Go запускает горутины, используя модель M:N:

  • M (machine) — поток ОС
  • G (goroutine) — горутина
  • P (processor) — контекст планировщика (логический процессор)
package main

import (
    "fmt"
    "runtime"
    "sync"
)

func main() {
    // Количество потоков ОС, которые может использовать Go
    fmt.Println("Max OS threads:", runtime.GOMAXPROCS(0))
    
    var wg sync.WaitGroup
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func(id int) {
            defer wg.Done()
            // Каждая горутина работает на одном из потоков пула
            fmt.Printf("Горутина %d выполняется\n", id)
        }(i)
    }
    wg.Wait()
}

Ключевые особенности потоков в контексте Go

  1. Многопоточность без блокировок: Go использует неблокирующий ввод-вывод и собственный планировщик, что позволяет эффективно использовать потоки ОС.

  2. Работа с блокирующими операциями: Если горутина выполняет блокирующий системный вызов (например, файловый ввод-вывод без использования netpoller), планировщик может создать новый поток ОС, чтобы другие горутины могли продолжать выполнение.

  3. Контроль над потоками: Программист может влиять на работу с потоками через:

    • runtime.GOMAXPROCS() — установка максимального числа потоков
    • runtime.LockOSThread() — привязка горутины к текущему потоку ОС
    • Настройки окружения (например, GOMAXPROCS)

Пример работы с привязкой к потоку

package main

import (
    "fmt"
    "runtime"
    "time"
)

func main() {
    // Привязываем горутину к текущему потоку ОС
    runtime.LockOSThread()
    defer runtime.UnlockOSThread()
    
    go func() {
        // Эта горутина может выполняться на другом потоке
        for i := 0; i < 3; i++ {
            fmt.Println("Другая горутина")
            time.Sleep(100 * time.Millisecond)
        }
    }()
    
    // Основная горутина гарантированно выполняется на закрепленном потоке
    fmt.Println("Основная горутина привязана к потоку")
    time.Sleep(300 * time.Millisecond)
}

Преимущества модели Go

  • Эффективность: Тысячи горутин могут работать на небольшом количестве потоков ОС
  • Автоматическое управление: Планировщик сам решает, когда создавать новые потоки или перепланировать горутины
  • Упрощенная модель программирования: Разработчик работает с горутинами и каналами, не управляя потоками напрямую

Когда потоки важны в Go

  1. Сторонние C-библиотеки, требующие привязки к потоку
  2. Графические приложения с UI-потоком
  3. Низкоуровневые системные вызовы с ограничениями по потокам
  4. Настройка производительности для специфичных рабочих нагрузок

Таким образом, в Go потоки ОС — это фундамент, на котором работает высокоуровневая модель горутин. Разработчику обычно не нужно работать с потоками напрямую, но понимание их роли важно для:

  • Отладки параллельных программ
  • Оптимизации производительности
  • Интеграции с системами, требующими работы с потоками
  • Понимания внутреннего устройства рантайма Go
Что такое поток? | PrepBro