Runtime Go состоит из следующих ключевых компонент: планировщик (scheduler), сборщик мусора (garbage collector) и система goroutine'ов.
Планировщик (ोसcheduler): Реализует многопоточность в пространстве пользователя (user-space threading). Он сопоставляет M (many) пользовательских горутин с N (few) потоками операционной системы. Использует модель M:N, которая эффективнее, чем 1:1 (каждая горутина — отдельный поток ОС) или N:1 (все горутины — один поток ОС). Планировщик управляет тремя очередями:
global run queue): горутины, которые еще не assigned к P.local run queue): горутины, assigned к конкретной P.wait queue): горутины, заблокированные по внешним причинам (сеть, файловый ввод/вывод).Модель планировщика основана на P (processor) - логическом процессоре, который связывает G (goroutine) и M (OS thread). M выполняет код G, а P предоставляет ресурсы и контекст для выполнения (локальную очередь горутин, кеш). Планировщик распределяет горутины между доступными M и P.
Сборщик мусора (Garbage Collector - GC): В Go используется конкурентный и параллельный сборщик мусора. Он работает concurrently с пользовательским кодом (stop-the-world фазы минимизированы) и параллельно (использует несколько ядер CPU). Алгоритм Mark-and-Sweep с триколорной схемой.
Финализация объектов также осуществляется runtime'ом.
Goroutine'ы: Легковесные, конкуретные функции, управляемые runtime Go, а не ОС. Они требуют меньше памяти (изначально 2KB стека, который может расти) и переключение между ними быстрее, чем между потоками ОС. Создаются с помощью ключевого слова go.
Коммуникация между горутинами происходит через каналы (channels), которые являются безопасным способом обмена данными и синхронизации.
go
Система ввода/вывода (I/O): Runtime Go использует неблокирующие I/O операции и мультиплексирование событий (например, epoll на Linux, kqueue на FreeBSD/macOS, IOCP на Windows). Когда горутина блокируется на I/O, runtime отсоединяет ее от M, позволяет M выполнять другую горутину, а когда I/O завершен, планировщик снова назначает горутине M (возможно, другую). Это позволяет эффективно использовать системные ресурсы и избегать блокировки потоков ОС.
Стек вызовов: Горутины используют растущий стек с изменяемым размером, который начинается с небольшого размера и увеличивается динамически по мере необходимости. Это уменьшает использование памяти по сравнению с потоками ОС, у которых обычно фиксированный (и больший) размер стека.
В целом, runtime Go спроектирован для обеспечения высокой производительности и конкурентности, управляя горутинами, памятью и системными ресурсами эффективно и прозрачно для разработчика.