Горутины обладают фиксированным начальным размером стека (обычно около 2 КБ), что позволяет создавать тысячи горутин без значительного потребления памяти. Это выгодно отличается от традиционных потоков, которые требуют значительно большего объема памяти для запуска.
Горутины работают независимо от основного потока программы. Это позволяет продолжать выполнение основной логики, пока фоновые горутины выполняют свои задачи.
При создании новой горутины ей выделяется минимальный объем памяти. Однако, если задача требует большего стека (например, при глубокой рекурсии), система автоматически расширяет его:
- Начальный размер: Новая горутина получает стек фиксированного размера (примерно 2 КБ).
- Расширение стека: Если горутина исчерпывает выделенный объем памяти, система создает новый блок памяти большего размера.
- Копирование данных: Все данные со старого стека копируются на новый.
- Продолжение выполнения: Горутина переключается на новый стек и продолжает выполнение.
Выполнение горутин управляется встроенным планировщиком Go. Он распределяет горутины по потокам системы, определяя порядок их выполнения. Планировщик работает асинхронно, что делает порядок завершения горутин непредсказуемым.
Для синхронизации выполнения горутин и предотвращения преждевременного завершения программы используется механизм
sync.WaitGroup. Этот инструмент позволяет основной горутине ожидать завершения всех дочерних задач перед завершением программы:- Code: Select all
package main
import (
"fmt"
"sync"
)
func worker(id int, wg *sync.WaitGroup) {
defer wg.Done() // Уменьшаем счетчик по завершении горутины
fmt.Printf("Worker %d started\n", id)
// Здесь выполняется какая-то работа
fmt.Printf("Worker %d finished\n", id)
}
func main() {
var wg sync.WaitGroup
for i := 1; i <= 5; i++ {
wg.Add(1) // Увеличиваем счетчик перед запуском новой горутины
go worker(i, &wg)
}
wg.Wait() // Ожидаем завершения всех горутин
fmt.Println("All workers finished")
}
Основная горутина создается автоматически при запуске программы. Если основная горутина завершает выполнение (например, достигает конца функции
main()), программа завершается, даже если другие горутины все еще работают. Чтобы избежать этого, используйте механизмы синхронизации, такие как sync.WaitGroup.