Какие виды конкурентности существуют
Что проверяют
Различаете ли вы конкурентность и параллелизм и знаете ли, какие модели взаимодействия задач даёт Go. Следом обычно просят показать гонку данных и объяснить, как её найти.
Как отвечать
Начните с разграничения: конкурентность это структура программы из независимо выполняемых задач, параллелизм это одновременное выполнение на нескольких ядрах. Конкурентная программа на одном ядре остаётся конкурентной.
Дальше модели:
- процессы: изолированная память, общение через IPC и сокеты. Надёжно, но дорого по памяти и переключению;
- потоки ОС: общая память, переключает ядро, у каждого потока фиксированный стек размером в мегабайты;
- горутины: их планирует рантайм Go по схеме M:N (модель G-M-P), стек стартует с 2 КБ и растёт по мере нужды. Одновременно исполняется не больше
GOMAXPROCSгорутин, по умолчанию это число доступных ядер. С Go 1.14 планировщик вытесняет горутины асинхронно, и плотный цикл без вызовов функций больше не блокирует остальных; - общая память с блокировками:
sync.Mutex,sync.RWMutex,sync/atomic; - передача сообщений (CSP): каналы и
select. Отсюда принцип «не общайтесь через общую память, делитесь памятью через общение».
Можно добавить деление на кооперативную и вытесняющую многозадачность и на I/O-bound и CPU-bound задачи: для сетевых горутин может быть десятки тысяч, а вычислительных больше GOMAXPROCS запускать бессмысленно.
Практика: sync.WaitGroup или errgroup для ожидания группы, context.Context для отмены, go test -race для поиска гонок.
Где спотыкаются
Считают каналы защитой от любых гонок. Если через канал передан указатель на структуру и обе горутины продолжают её менять, гонка остаётся.
Запускают горутину без способа её остановить. Горутина, навсегда заблокированная на чтении из канала, это утечка, заметная только по росту runtime.NumGoroutine().
Путают конкурентность с параллелизмом и обещают ускорение от горутин на вычислительной задаче при GOMAXPROCS=1. Горутины там будут чередоваться, но не работать одновременно.