Оператор go
Нагрузка на «Полку» выросла, и Миша вынес тяжёлый препроцессинг загрузок в фон: запрос стал отвечать сразу, а обработка пошла отдельной горутиной. Сергей попросил сразу продумать, как это всё останавливать.
go f запускает функцию в новой горутине и возвращается сразу; горутина — легковесный поток исполнения, которым управляет runtime, и по памяти на старте она в сотни раз дешевле потока ОС.
Запуск
go fetch(url)
fmt.Println("запустил, продолжаю")
fetch теперь работает конкурентно с остальной программой — реально параллельно исполняются не больше GOMAXPROCS горутин, — а главная горутина бежит дальше, не дожидаясь её. Аргументы и сама функция в go-выражении вычисляются в вызывающей горутине ещё до старта новой: дорогой вызов в аргументе задержит именно вызывающего. Это и есть горутина — легковесный поток выполнения, которым управляет runtime, а не операционная система.
Горутина — не поток
Поток ОС — дорогая вещь: стек в мегабайты, регистрация в ядре, своя запись в планировщике ОС. Горутина — структура в памяти runtime со стеком в пару килобайт, который растёт по мере надобности. Запустить сто тысяч потоков на обычной машине нельзя; сто тысяч горутин — нормальная нагрузка.
Горутина на единицу работы
Отсюда привычка, отличающая Go от других языков: горутину заводят не под «тяжёлую» задачу, а под каждую логическую единицу работы.
for _, conn := range conns {
go handle(conn) // горутина на соединение
}
Соединение, запрос, файл — на каждый можно завести горутину: сам запуск дёшев, но жизненный цикл горутины и число одновременных блокирующих операций контролируют отдельно (,,).
Вы узнаете:
- как растёт стек горутины
- как
runtime.NumGoroutineпомогает наблюдать
Проверьте себя
go func(){ time.Sleep(...); fmt.Println("из горутины") }(); fmt.Println("из main"). Что напечатается раньше?
Упадёт ли программа от запуска 100 000 горутин?
Замыкание в горутине захватывает переменную цикла path. Как гарантированно починить?
правильных ответов
go — запустить функцию конкурентно (аргументы вычисляются в вызывающей горутине до старта). Горутина дешевле потока в сотни раз по памяти на старте; её заводят под каждую единицу работы, а завершение и лимиты планируют отдельно. Как runtime исполняет их — уроки .
10 000 ₽ · 60 минут · онлайн