Как создаются горутины в Go и каковы их ключевые особенности?

Ответ

Горутины — это легковесные потоки, управляемые средой выполнения (runtime) Go.

Создание горутины

Горутина создается с помощью ключевого слова go, указанного перед вызовом функции. Эта функция (или метод) начинает выполняться асинхронно в новой горутине.

package main

import (
    "fmt"
    "time"
)

func sayHello() {
    fmt.Println("Привет из горутины!")
}

func main() {
    // Запускаем функцию sayHello в новой горутине
    go sayHello()

    fmt.Println("Привет из основной горутины (main)!")

    // Даём время на выполнение другой горутины, иначе main завершится раньше
    time.Sleep(100 * time.Millisecond)
}

Ключевые особенности:

  • Легковесность: Начальный размер стека горутины всего ~2 КБ, в то время как у потоков ОС он значительно больше (обычно 1-8 МБ). Это позволяет создавать сотни тысяч и даже миллионы горутин одновременно.
  • Управление средой выполнения: Планировщик Go (Go scheduler) эффективно распределяет горутины по реальным потокам ОС (модель M:N), обеспечивая высокий уровень параллелизма без больших накладных расходов на переключение контекста.
  • Быстрый запуск: Создание и запуск горутины происходит гораздо быстрее, чем создание потока ОС.
  • Коммуникация через каналы: Идиоматичный способ взаимодействия между горутинами — использование каналов (chan). Это помогает избежать состояний гонки при доступе к общим данным, следуя принципу: "Не обменивайтесь данными, разделяя память; разделяйте память, обмениваясь данными".
  • Общее адресное пространство: Все горутины выполняются в одном адресном пространстве, поэтому при доступе к общим данным без каналов необходимо использовать примитивы синхронизации (например, мьютексы из пакета sync).