Оглавление
Последовательное выполнениеКонкурентное выполнениеПараллельное выполнениеЧто такое горутинаАнонимные горутиныПланировщик GoКооперативное планированиеГлавная ловушка новичковКраткий итог
Почему горутины изменят ваше мышление о коде
16.02.2026

Я до сих пор помню свой первый запуск горутины. Только что перешёл с Java, где создание потока ощущалось как заполнение налоговой декларации: куча настроек, ExecutorService, пулы потоков и вечный страх, что всё рухнет в самый неподходящий момент.
А тут я просто написал
go перед вызовом функции.И всё. Никаких конфигураций. Никаких 15 строк подготовительного кода. Просто:
Но прежде чем углубляться в горутины, давайте разберёмся с базовыми понятиями, которые многие туториалы пролетают слишком быстро: последовательное, конкурентное и параллельное выполнение. Без этого фундамента дальше будет сложно.
Последовательное выполнение
Представьте кофейню с одним бариста. Приходит клиент, делает заказ, бариста полностью готовит напиток, отдаёт его и только потом зовёт следующего.
Это последовательное выполнение. Один процессор, одна задача за раз — от начала до конца.
Три заказа — шесть секунд. Каждый следующий ждёт, пока закончится предыдущий.
Конкурентное выполнение
Тот же один бариста, но очень ловкий. Он запускает кофемашину для эспрессо, а пока она работает — параллельно взбивает молоко для латте. Он не делает два дела одновременно в буквальном смысле, а быстро переключается между ними.
Это и есть конкурентность. Один процессор, несколько задач в работе одновременно. Ключевое слово — в работе, а не "одновременно".
Все три заказа стартуют почти мгновенно. Общее время около двух секунд. Тот же один процессор, но пропускная способность выросла в разы.
Параллельное выполнение
Теперь в кофейне три бариста. Каждый делает свой заказ одновременно, без всякого переключения.
Это параллелизм. Несколько ядер, каждая задача выполняется на своём ядре независимо.
Важный момент, который часто путают:
Конкурентность — это про структуру кода.
Параллелизм — это про исполнение.
Вы можете писать конкурентный код, который будет работать даже на одном ядре. А параллелизм без нескольких ядер невозможен.
Go прекрасно это разделяет. Вы пишете конкурентный код с помощью горутин, а рантайм сам решает, запускать ли их параллельно в зависимости от количества доступных ядер.
Что такое горутина
Горутина — это функция, которая выполняется конкурентно с другими функциями. Всё. Никаких специальных классов, интерфейсов или наследования. Просто ключевое слово
go.За кулисами горутина — это не OS-поток. Она намного легче. Обычному потоку нужно около 1 МБ стека, горутине — всего 2 КБ в начале (и стек растёт по мере необходимости). Можно запустить десятки и сотни тысяч горутин без особых проблем.
Анонимные горутины
Иногда не хочется создавать отдельную функцию. Можно запустить код конкурентно прямо на месте:
Синтаксис поначалу выглядит странно (определение функции + сразу вызов
()), но к нему быстро привыкаешь. В реальном Go-коде анонимные горутины встречаются повсеместно.Планировщик Go
Когда запускается Go-программа, рантайм создаёт несколько OS-потоков и распределяет по ним горутины (M:N-планирование). Это делается через три основных сущности:
- G — горутина
- M — OS-поток (компьютер)
- P — логический процессор (контекст планирования)
У каждого P есть своя локальная очередь горутин (Local Run Queue - LRQ) и есть глобальная очередь (Global Run Queue - GRQ).
Планировщик сам решает, когда и какую горутину запустить. Если горутина блокируется (например, на сетевом запросе), её просто вытесняют и ставят другую — вы этого даже не замечаете.
Кооперативное планирование
Планировщик Go кооперативный (не вытесняющий). Горутины сами отдают управление в определённых точках:
- Вызов любой функции
- Операции с каналами
- Сетевой ввод/вывод
- Сборка мусора
- Запуск новой горутины (
go)
Поэтому теоретически можно написать горутину в бесконечном цикле без единого вызова функции, которая зажмёт ядро. На практике такое почти не встречается, потому что почти всегда есть либо I/O, либо работа с каналами.
Главная ловушка новичков
Самая частая ошибка: когда завершается
main(), программа сразу завершается, убивая все остальные горутины.Поэтому в примерах мы использовали
time.Sleep — это удобно для демонстрации, но в реальном коде так делать нельзя. Правильные решения — sync.WaitGroup и каналы.Краткий итог
- Последовательное — просто, но медленно.
- Конкурентное — несколько задач в работе, быстрое переключение.
- Параллельное — настоящее одновременное выполнение на разных ядрах.
- Горутины — лёгкие, управляемые рантаймом Go, невероятно дешёвые.
- Планировщик использует M:N-модель и локальные очереди.
- Главная горутина завершилась, значит всё умерло.
Горутины — это не просто инструмент для ускорения. Это другой способ мышления о коде. После них многие привычные подходы кажутся тяжёлыми и архаичными.

