Многопоточность и многопроцессорность
Что такое GIL (Global Interpreter Lock)?
GIL в обычной сборке CPython допускает выполнение байт-кода только одним потоком за раз в одном интерпретаторе. При блокирующем вводе-выводе и в некоторых расширениях на C он освобождается. Это ограничивает параллелизм вычислений на Python, но не исключает полезную многопоточность. Начиная с CPython 3.13 доступны отдельные free-threaded сборки без GIL.
Ссылки для изучения
Примеры хороших ответов из реальных собеседований
- Мок-интервью Python-разработчика: ООП и PostgreSQL · 44:48–45:13Мок-собеседование · Ответ кандидата
Кандидат расшифровывает GIL и объясняет, что в один момент только один поток исполняет Python bytecode.
В чем отличие multiprocessing от multithreading в Python?
Отличие между multiprocessing и multithreading в Python заключается в том, как они обрабатывают параллелизм:
Multiprocessing:
-
multiprocessingпозволяет создавать отдельные процессы для выполнения задач. -
Каждый процесс имеет свое собственное пространство памяти, что делает его более надежным при работе с разделяемой памятью и предотвращает проблемы с GIL.
-
Это подходит для CPU-интенсивных задач, которые могут быть распараллелены, так как каждый процесс может использовать отдельное ядро процессора.
Multithreading:
-
multithreadingсоздает несколько потоков внутри одного процесса для выполнения задач. -
Потоки разделяют общее пространство памяти процесса, что может привести к проблемам с синхронизацией доступа к общим ресурсам.
-
Это подходит для задач с большим количеством ввода-вывода (I/O-bound), так как потоки могут блокироваться при ожидании завершения операций ввода-вывода.
В целом, multiprocessing обеспечивает большую изоляцию и параллелизм, в то время как multithreading может быть эффективным для задач, требующих ввода-вывода, но может столкнуться с проблемами с синхронизацией при доступе к общим ресурсам.
Ссылки для изучения
Примеры хороших ответов из реальных собеседований
- Разбор технического собеседования Python-разработчика · 1:12:55–1:14:00Разбор интервью · Ответ кандидата
Кандидат выбирает multiprocessing для CPU-bound вычислений, а потоки для I/O с сетью, файлами и базой данных.
Каковы различия между IO-bound и CPU-bound задачами?
Различия между IO-bound и CPU-bound задачами связаны с тем, какие ресурсы больше всего использует каждая из них:
IO-bound задачи:
-
Эти задачи в основном зависят от операций ввода-вывода (IO), таких как чтение и запись файлов, сетевые запросы и т. д.
-
Примеры IO-bound задач включают загрузку веб-страниц, чтение больших файлов, обращение к базам данных и т. д.
-
В таких задачах основное время ожидания затрачивается на ожидание завершения операций ввода-вывода, а не на обработку данных.
CPU-bound задачи:
-
Эти задачи требуют большого количества вычислительных ресурсов процессора (CPU).
-
Примеры CPU-bound задач включают математические вычисления, обработку данных, компиляцию программ и т. д.
-
В таких задачах основное время затрачивается на обработку данных или выполнение алгоритмов, а не на ожидание операций ввода-вывода.
Ссылки для изучения
Примеры хороших ответов из реальных собеседований
- Python: техническое собеседование Junior-разработчика · 33:20–34:25Мок-собеседование · Совместный разбор
Кандидат и интервьюер различают CPU-bound вычисления и ожидание I/O, затем показывают, почему вычисления блокируют event loop.
Где лучше использовать потоки и асинхронность в Python?
Потоки подходят для конкурентного выполнения блокирующего ввода-вывода, особенно если библиотеки имеют синхронный API. В обычной сборке CPython GIL мешает потокам параллельно выполнять CPU-bound код на Python, поэтому для тяжёлых вычислений чаще используют процессы. Исключения: расширения, которые освобождают GIL, и free-threaded сборки Python.
asyncio удобно для большого числа одновременно ожидающих операций, если весь стек поддерживает неблокирующий async API. Оно работает в одном потоке, переключая корутины в точках await, поэтому блокирующий вызов внутри event loop останавливает остальные задачи.
Подробнее: потоки и asyncio в документации Python.
Ссылки для изучения
Примеры хороших ответов из реальных собеседований
- Тестовое Middle Python-интервью о GIL и конкурентности · 37:07–38:15Мок-собеседование · Совместный разбор
Кандидат выбирает процессы для параллельной обработки изображений, а потоки или asyncio для I/O-bound операций.
Почему GIL не устраняет гонки данных?
GIL в обычной сборке CPython разрешает исполнять Python bytecode одному потоку за раз, но составная операция состоит из нескольких шагов, между которыми возможно переключение; C-расширение также может отпустить GIL. Поэтому read-modify-write общего объекта остается гонкой. Критическую секцию защищают Lock или убирают совместное изменяемое состояние. Free-threaded CPython делает зависимость от GIL еще менее допустимой. Корректность проверяют под конкуренцией и при завершении процесса, потому что последовательный тест не обнаруживает гонку.
Ссылки для изучения
Как процессам безопасно разделять данные?
Процессы имеют раздельную память. Небольшие сообщения безопаснее передавать через multiprocessing.Queue или pipe с ценой сериализации. Для больших буферов подходит shared memory, а Value и Array дают простые разделяемые значения; доступ к составному состоянию синхронизируют Lock или Semaphore. Manager удобен, но прокси и отдельный server process дороже. Владелец и жизненный цикл shared segment должны быть явными. Корректность проверяют под конкуренцией и при завершении процесса, потому что последовательный тест не обнаруживает гонку.
Ссылки для изучения
Как выбрать примитив синхронизации потоков?
Lock защищает одну критическую секцию, RLock допускает повторный вход того же потока, Semaphore ограничивает число одновременных владельцев ресурса. Event сообщает факт наступления состояния, а Condition позволяет ждать предикат под общей блокировкой и перепроверять его в цикле. Примитив выбирают из протокола взаимодействия. Он не исправляет слишком крупную общую mutable-state модель и может добавить дедлоки. Корректность проверяют под конкуренцией и при завершении процесса, потому что последовательный тест не обнаруживает гонку.
Ссылки для изучения







