// день 2 из 7
Конкурентность
Горутины и GMP, каналы, select, sync, context.
Утро — горутины, каналы, sync, context. День — «что выведет» на конкурентность и задачи с -race. Вечер — мок.
Пока пусто. Ответь на первые вопросы — здесь появится готовность по этапам.
Вечером — мок: Секция конкурентности
График в роли интервьюера, один вопрос за раз, в конце — отчёт и вердикт для Middle.
Один пробный мок — бесплатно, дальше — Pro или Спринт.
Вопросы
0/60- Какие примитивы синхронизации в Go вы знаете? Расскажите про них.free
- Расскажи про модель GMP / устройство планировщика Gofree
- Что такое каналы в Go и зачем они нужны (как средство коммуникации горутин)?free
- Что такое горутины и зачем они нужны?free
- В чём разница между процессом и потоком (и горутиной)?
- Что происходит при чтении из закрытого канала и при записи в закрытый канал?
- Как устроены каналы в Go под капотом?
- Что происходит с горутиной при блокирующем системном вызове / сетевом обращении, и как работает netpoller?
- RWMutex vs Mutex — в чём разница?
- Что такое context.Context, зачем он нужен в Go?
- Чем горутины отличаются от потоков операционной системы?
- Какие типы/виды каналов бывают?
- Для чего нужен select? Как он работает, что произойдёт, если ни один канал не готов, и как привести повседневный пример использования?
- Что такое race condition? Как его избежать? (в т.ч. сценарий: множество горутин пишут в одну переменную без синхронизации — что будет?)
- Что такое и что задаёт значение GOMAXPROCS?
- Как работает планировщик и как устроены его очереди (local/global run queue)? Планировщик работает по принципу work stealing или work sharing?
- Что такое sync.Pool и как он используется? Приходилось ли пользоваться на практике?
- Какие виды context бывают? Какие у пакета context методы?
- Почему горутины лёгковесны?
- Какой вид многозадачности используется в Go? Чем планировщик до версии 1.14 отличается от планировщика после (кооперативная vs вытесняющая)?
- Как устроен RWMutex под капотом? Расскажи про RWMutex.
- Расскажи про атомики: зачем нужны, от чего защищают.
- В чём разница между буферизованным каналом (ёмкостью 1) и небуферизованным каналом? Одинаково ли они работают?
- Сколько горутин можно создать? Чем ограничено их количество?
- Что происходит в рантайме, когда выполняется `go func()`?
- Зачем вообще нужен планировщик Go, если ОС и так переключает потоки?
- Чем занимается runtime Go? Как он управляет потоками?
- По каким критериям происходит переключение (вытеснение) горутин планировщиком?
- Что такое утечка горутин? Как понять, что горутины текут на реальном проекте?
- Как передать данные между двумя процессами / двумя локально запущенными Go-программами?
- Что произойдёт, если горутины, запущенные в цикле, захватывают переменную цикла в замыкании? Как это поведение изменилось в Go 1.22?
- В чём разница между data race и race condition?
- Какой context корректно передавать вниз по вызовам (например, из HTTP-обработчика)? Почему ctx принято передавать первым аргументом функции?
- Чем отличается конкурентность от параллелизма? Может ли быть параллелизм на одном ядре?
- Что такое deadlock и когда он происходит?
- Что такое Mutex и зачем он нужен?
- Всегда ли имеет смысл создавать горутины? Когда их стоит использовать?
- Что такое P — логический процессор в модели GMP?
- Приложение работало на одном ядре CPU, добавили второе, но оно всё равно использует только одно ядро. Почему?
- Как без изменения кода запустить программу так, чтобы горутины исполнялись только на одном логическом процессоре (GOMAXPROCS=1 через переменную окружения), и как это повлияет на её поведение?
- Если запустить 100 операций вычисления квадратного корня в 100 горутинах, получим ли прирост производительности?
- Процессор с 4 ядрами и 8 потоками, создаём 100 горутин с бесконечным `for` в каждой — что будет?
- Если GOMAXPROCS=1 и две горутины содержат только `for{}` (последняя версия Go) — будет ли переключение между ними?
- Что делает функция `runtime.Gosched()`?
- Расскажите про голодающие горутины (starvation).
- Как планировщик работает с каналами? Где находятся горутины, ожидающие чтения/записи в канал?
- Какой вариант коммуникации в общем случае более дорогостоящий — межпотоковое или межпроцессное взаимодействие — и почему?
- Есть система с двумя процессами, их указатели случайно совпали по значению — ссылаются ли они на одну физическую область памяти? Что такое виртуальная память?
- Знаком с паттерном guard close — как безопасно закрыть канал, в который пишут несколько горутин?
- Как в select обрабатывается чтение из закрытого канала?
- Как называется структура данных, с помощью которой реализован буфер каналов (кольцевой буфер)? В чём преимущество этой структуры?
- Когда могут возникать паники при использовании sync.WaitGroup?
- Как реализовать синглтон для job'ы? (подсказка: sync.Once)
- Какой нюанс при работе с sync.Pool связан с персистентностью (хранением данных)?
- Почему атомики быстрее мьютексов?
- Расскажите про алгоритм atomic.CompareAndSwap.
- В чём разница между data race, race condition и deadlock?
- Что такое дедлок? Как достичь дедлока, если есть два мьютекса?
- Будет ли паника в случае гонки данных с переменной в рантайме?
- Что такое deadlock и race condition? Как их отслеживать и предотвращать?
Ещё 33 · вопрос — если осталось время или хочешь глубже
- Что такое Deadlock и Livelock? В чём отличие?
- Какие потокобезопасные структуры данных в Go ты знаешь?
- Какое действие нельзя делать со всеми примитивами синхронизации?
- Делаем нагрузочное тестирование, данные с запросов складываем в in-memory хранилище. Что лучше использовать — каналы или мьютексы? Что будет работать быстрее?
- Как сделать параллельно 5 запросов к стороннему сервису и получить общий результат по всем запросам?
- В паттерне Producer-Consumer какую роль играет буферная очередь и какую архитектурную проблему она решает?
- Что такое генераторы, например в PHP, и как сделать их реализацию в Go?
- Что такое graceful shutdown? Реализовывал ли? Как это работает?
- Есть структура Account (Number, Balance) и функция Transfer(from, to Account, amount float64) error. Если все данные хранятся в памяти — как должна работать логика перевода средств? Рассказать словами, без кода.
- Какая команда/инструмент помогает проверить и найти гонки или дедлоки? (go run/test -race)
- Можно ли закрыть канал повторно (double close)? Что произойдёт?
- Как понять, закрыт канал или нет (идиома `v, ok := <-ch`)? Как проверить, что при чтении получено валидное значение?
- Сводный вопрос: что происходит при чтении/записи/повторном закрытии закрытого канала и при работе с nil-каналом?
- Что произойдёт, если записать в канал, у которого нет читателя (горутина блокируется навсегда)?
- Как запретить чтение или запись в канал (направленные каналы, `chan<-` / `<-chan`)?
- Что такое data race?
- Какие механизмы/инструменты конкурентности есть в Go (каналы и другие)?
- Что такое асинхронность?
- Как вычитать значение из канала?
- В каких случаях при работе с каналами возникает паника?
- Что будет, если делать range по nil-каналу? Что происходит при чтении/записи в nil-канал?
- Что такое select? Обязательно ли запускать его в бесконечном цикле? Продолжится ли выполнение, если в select два кейса, а каналам нечего отдавать?
- Как читать из нескольких каналов одновременно, не блокируясь, если данных нет (select + default)?
- В чём отличие switch и select?
- В чём основное отличие каналов от массивов в Go?
- При чтении канала через range какие есть особенности? Как узнать, сколько элементов в буферизированном канале? Какая длина у небуферизированного канала?
- Почему в канал передают пустую структуру (`struct{}`), а не пустой интерфейс?
- Какой метод используется для блокировки мьютекса в Go?
- Какой порядок использования методов sync.WaitGroup считается корректным при закрытии набора горутин?
- Какие методы есть у sync.WaitGroup и что делает каждый из них?
- Если только читаем из мапы из разных горутин — нужно ли её лочить?
- Будет ли паника в случае deadlock-а?
- Расскажите, в каких задачах вы применяли конкурентную (асинхронную) обработку данных в Go.
Что выведет
0/15- <-spawn(), <-spawn(): 3 или 6?
- select: отправка в закрытый канал против чтения из закрытого
- 120 HTTP-запросов при GOMAXPROCS(1)
- 120 чтений файлов при GOMAXPROCS(1)
- Бесконечная запись по указателю при GOMAXPROCS(1)
- defer close в функции, которая читает канал
- 64 продюсера закрывают общий канал
- select на чтение и запись одного канала ёмкостью 1
- Три категории, три канала, один select
- Буфер ёмкостью 1 и фоновая горутина со sleep
- Две отправки в канал, который слушает горутина
- select на чтение и запись одного небуферизованного канала
- Воркеры под мьютексом и бесконечный цикл чтения
- Читатель и писатель одной map без мьютекса
- Три горутины пишут в один ключ map
Ещё 22 · что выведет — если осталось время или хочешь глубже
- Mutex в value-ресивере
- Сумма 1..10 через горутины даёт около 100
- Дочерний WithTimeout и дедлайн родителя
- Максимум из 1000 горутин без ожидания
- WaitGroup на первую горутину, вторая — без ожидания
- 10 000 последовательных запросов по 1 мс
- Горутины в цикле range по int
- 8000 горутин и печать счётчика
- Горутина и печать в main
- Отправка и close небуферизованного канала в main
- Запись и чтение небуферизованного канала в одной горутине
- WaitGroup перед чтением небуферизованного канала
- Отправка в nil-канал из нескольких горутин
- Сигнал завершения раньше чтения данных
- Минимальный гарантированный deadlock
- Счётчик из 12 горутин и Sleep вместо ожидания
- Повторный Lock того же мьютекса
- 12 000 «сетевых вызовов» в горутинах
- WaitGroup есть, а счётчик всё равно врёт
- 12 000 горутин пишут в одну переменную
- Две строки, одна из горутины
- 0 или 1: успела ли задача до тайм-аута
Лайвкодинг
0/1Открытые задачи
0/2- select с двумя одинаковыми case по закрытому каналу5 мин
- Горутина пишет в канал данных и канал ошибок15 мин
Ещё 11 · задача — если осталось время или хочешь глубже
- Конкурентная запись в map через каналы15 мин
- Фоновое обновление курсов без синхронизации15 мин
- Префиксное дерево с RWMutex на узел10 мин
- Одна и та же map в канале: агрегация партий15 мин
- wg.Done() в начале горутины7 мин
- Конкурентный логгер20 мин
- Конкурентная запись в map с помощью атомиков15 мин
- Отправка из горутины, чтение через select и доработка до range5 мин
- Горутины без ожидания завершения3 мин
- Вывод stage-функций через небуферизованный канал10 мин
- Горутина-эхо10 мин