Что такое runtime в Go и зачем он нужен
Что проверяют
Понимаете ли вы, что язык делает за вас во время выполнения и чем вы за это платите. Вопрос почти всегда ведёт дальше: к планировщику горутин, к сборщику мусора и к тому, почему чтение из сокета не занимает поток операционной системы.
Как отвечать
Runtime в Go это не виртуальная машина и не отдельный процесс, а библиотека, вкомпилированная в каждый бинарник. Поэтому программа собирается в один исполняемый файл и не требует установленной среды на целевой машине.
Что он берёт на себя:
- планировщик: горутины раскладываются по логическим процессорам и потокам ОС, с перехватом работы у соседей и вытеснением долго считающих горутин;
- стеки: горутина стартует с маленького стека и растёт копированием, отсюда дешевизна сотен тысяч горутин;
- сборщик мусора: конкурентная пометка и очистка, без поколений и без перемещения объектов; паузы короткие, плата идёт пропускной способностью;
- сетевой поллер: ожидание на сокете снимает горутину с потока, а поток уходит выполнять другую работу;
- системные вызовы, panic, recover и defer, реализация map, каналов и интерфейсов, профилировщик и трассировка.
Управляют этим немногими ручками: GOMAXPROCS, GOGC, GOMEMLIMIT, а смотрят через pprof и go tool trace.
Где спотыкаются
Называют runtime виртуальной машиной и приписывают ему JIT. Go компилируется заранее в машинный код, интерпретации нет, runtime это обычные функции, слинкованные рядом с вашим кодом.
Путают конкурентность и параллелизм. Горутины конкурентны всегда, а параллельно исполняются ровно настолько, насколько позволяют доступные ядра и значение GOMAXPROCS.
Считают, что сборщик мусора закрывает все вопросы с памятью. Он не трогает то, на что есть живая ссылка: горутина, навсегда зависшая на канале, глобальная map без вытеснения, срез, удерживающий большой массив ради пары элементов. Это утечки, и ищут их профилем кучи, а не жалобами на сборщик.