Материал проходит вычитку — возможны неточности.
Урок 66 из 118

Оператор go

Нагрузка на «Полку» выросла, и Миша вынес тяжёлый препроцессинг загрузок в фон: запрос стал отвечать сразу, а обработка пошла отдельной горутиной. Сергей попросил сразу продумать, как это всё останавливать.

Главная мысль

go f запускает функцию в новой горутине и возвращается сразу; горутина — легковесный поток исполнения, которым управляет runtime, и по памяти на старте она в сотни раз дешевле потока ОС.

Запуск

go fetch(url)
fmt.Println("запустил, продолжаю")

fetch теперь работает конкурентно с остальной программой — реально параллельно исполняются не больше GOMAXPROCS горутин, — а главная горутина бежит дальше, не дожидаясь её. Аргументы и сама функция в go-выражении вычисляются в вызывающей горутине ещё до старта новой: дорогой вызов в аргументе задержит именно вызывающего. Это и есть горутина — легковесный поток выполнения, которым управляет runtime, а не операционная система.

Горутина — не поток

Поток ОС — дорогая вещь: стек в мегабайты, регистрация в ядре, своя запись в планировщике ОС. Горутина — структура в памяти runtime со стеком в пару килобайт, который растёт по мере надобности. Запустить сто тысяч потоков на обычной машине нельзя; сто тысяч горутин — нормальная нагрузка.

Горутина на единицу работы

Отсюда привычка, отличающая Go от других языков: горутину заводят не под «тяжёлую» задачу, а под каждую логическую единицу работы.

for _, conn := range conns {
    go handle(conn) // горутина на соединение
}

Соединение, запрос, файл — на каждый можно завести горутину: сам запуск дёшев, но жизненный цикл горутины и число одновременных блокирующих операций контролируют отдельно (,,).

В следующем уроке

Вы узнаете:

  • как растёт стек горутины
  • как runtime.NumGoroutine помогает наблюдать
Задание · вопросы

Проверьте себя

Вопрос 1 из 3

go func(){ time.Sleep(...); fmt.Println("из горутины") }(); fmt.Println("из main"). Что напечатается раньше?

Вопрос 2 из 3

Упадёт ли программа от запуска 100 000 горутин?

Вопрос 3 из 3

Замыкание в горутине захватывает переменную цикла path. Как гарантированно починить?

Итоги

go — запустить функцию конкурентно (аргументы вычисляются в вызывающей горутине до старта). Горутина дешевле потока в сотни раз по памяти на старте; её заводят под каждую единицу работы, а завершение и лимиты планируют отдельно. Как runtime исполняет их — уроки .

Наш сайт собирает куки. Чтобы тебе было удобнее им пользоваться. Нажимая на кнопку, ты даёшь разрешение собирать куки