Что такое тред (поток) и как он соотносится с горутинами в Go?

Ответ

Тред (поток выполнения) — это наименьшая единица выполнения кода, которой операционная система может управлять независимо. Каждый процесс имеет как минимум один тред.

Ключевые характеристики тредов (OS Threads):

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

Связь с горутинами в Go

Горутины — это не треды операционной системы. Это легковесные, абстрактные потоки выполнения, управляемые планировщиком Go (Go Runtime Scheduler).

  • Легковесность: Горутины имеют небольшой начальный размер стека (около 2 КБ), который может динамически расти. Создание сотен тысяч горутин — обычная практика, в то время как создание такого же количества тредов ОС привело бы к исчерпанию системных ресурсов.
  • Модель M:N: Планировщик Go реализует модель M:N, где M горутин выполняются на N тредах операционной системы. Это позволяет эффективно использовать процессорное время, так как если одна горутина блокируется (например, на операции ввода-вывода), планировщик может переключить на выполнение другую горутину на том же треде ОС, не блокируя сам тред.
  • Переключение контекста: Переключение между горутинами происходит в пространстве пользователя (user space) и выполняется планировщиком Go, что на порядки быстрее, чем переключение контекста тредов ОС.

Пример на Go:

package main

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

func worker(id int, wg *sync.WaitGroup) {
    defer wg.Done()
    fmt.Printf("Горутина %d начала работуn", id)
    time.Sleep(time.Second)
    fmt.Printf("Горутина %d завершила работуn", id)
}

func main() {
    var wg sync.WaitGroup
    // Запускаем 3 горутины, которые могут выполняться параллельно
    for i := 1; i <= 3; i++ {
        wg.Add(1)
        go worker(i, &wg) // Запуск горутины, а не треда ОС
    }
    // Ожидаем завершения всех горутин
    wg.Wait()
    fmt.Println("Все горутины завершены.")
}

Итог: Горутины — это высокоуровневая и более эффективная концепция для конкурентного программирования в Go, которая абстрагирует разработчика от сложностей прямого управления тредами ОС.