Что в Go хорошо сделано для синхронности?
Что проверяют
Понимаете ли вы, почему конкурентность в Go считается удачной, и видите ли слабые места.
Как отвечать
Сильные стороны по пунктам.
1. Дешёвые горутины. Стек начинается с пары килобайт и растёт по мере надобности, создание стоит микросекунды. Миллион горутин это нормальная ситуация, а миллион потоков невозможен. Отсюда можно не экономить и запускать горутину на каждую задачу.
2. Блокирующий код при неблокирующем исполнении. Вы пишете обычное последовательное чтение из сети, а под капотом операция уходит в опрашиватель ядра, и поток освобождается. Получается читаемость синхронного кода с эффективностью асинхронного, без разделения функций на обычные и асинхронные и без окрашивания вызовов.
3. Каналы и конструкция выбора как часть языка. Не библиотека, а синтаксис: передача данных, ожидание нескольких источников, таймаут и отмена выражаются коротко и единообразно.
4. Планировщик с локальными очередями и кражей работы у соседей балансирует нагрузку сам, а блокирующий системный вызов не останавливает остальных.
5. Отмена через контекст как общепринятое соглашение: единый способ прервать дерево вызовов, принятый всей экосистемой.
6. Детектор гонок прямо в инструментах. Одна опция при запуске тестов, и конкурентные ошибки, которые иначе плавают месяцами, находятся сразу. Это очень недооценённая часть.
Слабые места назвать обязательно, иначе ответ выглядит рекламой:
- нет структурированной конкурентности из коробки. Запущенная горутина никем не ограничена, и утечки получаются легко: отправитель ждёт читателя, которого больше нет. Обнаруживается только в профиле;
- ошибки из горутин приходится собирать вручную, отсюда популярность отдельной библиотеки для групп;
- паника в горутине роняет весь процесс, перехватить её снаружи нельзя.
Где спотыкаются
Называют только дешевизну горутин.
Не упоминают опрашиватель сети и объясняют эффективность одним планировщиком.
Не видят проблемы утечек горутин.
Не пользуются детектором гонок.