Сначала отвечай сам и только потом проверяй ответ 👇
Стэк: Python
Вопрос: Что такое GIL?
Ответ:
GIL (Global Interpreter Lock) — это мьютекс в CPython, который позволяет исполнять байт-код Python строго одному потоку в один момент времени.
Зачем нужен: Защищает внутренний механизм управления памятью (подсчёт ссылок) от состояния гонки. Из-за этого threading не даёт параллелизма в CPU-bound задачах.
Как обходят:
• multiprocessing — у каждого процесса создаётся свой GIL и своя память.
• I/O и C-расширения (numpy, pandas) — отпускают GIL во время сложных вычислений или ожидания сети/файлов.
• Python 3.13+ — появился официальный режим отключения GIL (free-threaded).
Сначала отвечай сам и только потом проверяй ответ 👇
Стек: Go
Вопрос:
«Что происходит с процессором (P), если поток (M) заблокирован системным вызовом?»
Ответ:
В планировщике Go (в рамках модели G-M-P) логический процессор (P) — это ресурс, необходимый для выполнения горутин. Планировщик не может позволить ему простаивать.
Если поток операционной системы (M) жестко блокируется (например, при тяжелом системном вызове ввода/вывода), планировщик отсоединяет P от этого заблокированного M. Затем он находит другой свободный поток M в пуле (или создает новый) и прикрепляет P к нему.
Благодаря этой механике отвязки, логический процессор P продолжает непрерывно выполнять другие горутины из своей локальной очереди. А заблокированный поток M спокойно ждет ответа от ОС в фоне, не тормозя работу всей программы.
Сначала отвечай сам и только потом проверяй ответ 👇
Стек: Go
Вопрос:
«В чем главные подводные камни функции append при работе со слайсами?»
Ответ:
Слайс - это лишь «обертка» над базовым массивом. Главный подводный камень заключается в том, что если несколько слайсов ссылаются на один и тот же массив, изменение элементов через один слайс затронет и все остальные.
Но ситуация резко меняется при вызове append. Если при добавлении элемента текущая вместимость (capacity) слайса превышена, Go выделит в памяти новый массив, скопирует туда данные и добавит новый элемент.
С этого момента связь между слайсами разрывается! Ваш обновленный слайс начнет смотреть на новый участок памяти, а старые слайсы продолжат смотреть на старый. Это частый источник трудноуловимых багов, когда разработчик думает, что мутирует исходные данные, а по факту работает уже с независимой копией.
Сначала отвечай сам и только потом проверяй ответ 👇
Вопрос:
«Почему нельзя указывать в функции аргумент по умолчанию как пустой изменяемый объект (например, список или словарь)?»
Стек: Python
Ответ:
Потому что этот объект будет создан ровно один раз - на этапе определения (инициализации) функции в памяти.
Из-за этого при каждом следующем вызове функции без явного указания аргумента будет переиспользоваться один и тот же объект. Он начнёт накапливать в себе значения от предыдущих вызовов, что приведёт к непредсказуемому поведению программы.
💡 Как делать правильно: использовать None в качестве значения по умолчанию, а внутри тела функции делать проверку и создавать новый пустой список или словарь.
Ходишь по техническим собеседованиям, но в ответ получаешь только «к сожалению, мы выбрали другого»? 🧐
Типичный сценарий: сходил на интервью, где-то поплыл, получил отказ. По привычке открыл «топ-500 вопросов», освежил базы данных, пошёл на следующее — и снова всё повторилось.
Проблема в том, что хаотичная зубрёжка теории между собесами ничего не меняет. Ты просто переносишь одни и те же незамеченные ошибки с одной встречи на другую.
В новом видео мы разобрали системный 6-этапный алгоритм подготовки, который превращает любой пройденный собес в понятный план действий:
— Как готовиться под конкретную компанию, а не читать всё подряд
— Зачем записывать встречи через OBS и переводить в текст через Whisper
— Как искать реальные пробелы в знаниях с помощью нейросетей
— Как правильно отрабатывать ошибки на практике и проверять себя перед следующим шагом
Сначала отвечай сам и только потом проверяй ответ 👇
Стек: Go
Вопрос:
«Как работает sync.WaitGroup и зачем нужен метод Done()?»
Ответ:
sync.WaitGroup - это потокобезопасный счетчик, который нужен для того, чтобы дождаться завершения группы горутин.
Как он работает под капотом:
Add(n) - увеличивает внутренний счетчик на n (обычно вызывается перед запуском горутин).
Done() - уменьшает счетчик на 1. Фактически, под капотом это просто синоним вызова Add(-1). Чаще всего его вызывают через defer внутри самой горутины, чтобы гарантировать уменьшение счетчика при любом исходе.
Wait() — блокирует выполнение текущей горутины (например, main), пока счетчик не опустится до нуля.
Как только все запущенные горутины отработают и вызовут Done(), счетчик станет равен 0, блокировка снимется, и программа продолжит работу.
Сначала отвечай сам и только потом проверяй ответ 👇
Вопрос:
«В чём отличие корутин от future и task?»
Стек: Python
Ответ:
Корутина - это объект, возвращаемый асинхронной функцией. Она может выполняться асинхронно, приостанавливать и возобновлять своё выполнение при встрече с ключевым словом await.
Future - это низкоуровневый объект, который представляет собой «обещание» получить результат операции в будущем. Он хранит состояние асинхронной задачи: незавершённое, завершённое с результатом или завершённое с ошибкой. Future используется для передачи результатов между частями асинхронного кода, и его тоже можно ждать через await.
Task - это подкласс Future. Главное отличие в том, что при создании Task вы напрямую планируете выполнение корутины в цикле событий (Event Loop), а её результат уже сохраняется как Future.
💡 Краткий вывод: Корутина описывает логику асинхронных операций (что делать), Future представляет результат этих операций (что получилось), а Task является оберткой, которая планирует и запускает корутину в работу.