Вопрос с собеседования · Python

Какие ограничения есть у multiprocessing и чем fork отличается от spawn?

MiddleКонкурентность
Ещё спрашивают так:
  • Почему ProcessPoolExecutor не принимает лямбду?
  • Как процессы в Python обмениваются данными?
Коротко

Процессы не делят память: аргументы и результаты сериализуются pickle и копируются. Лямбды, локальные функции, открытые файлы и соединения не сериализуются. fork копирует процесс родителя (быстро, но опасно с потоками), spawn запускает чистый интерпретатор и импортирует модуль заново (нужна защита if __name__ == "__main__").

  • По умолчанию: Linux — fork (с 3.14 — forkserver), macOS и Windows — spawn
  • Общие данные — Queue, Pipe, Manager, shared_memory
  • Большие данные гонять через pickle дорого — передавать пути или использовать shared_memory

А ещё fork после запуска потоков может унаследовать захваченную блокировку и зависнуть

Подробно

Почему pickle. Процесс — отдельное адресное пространство. Чтобы передать задачу, пул сериализует функцию (по имени модуля и функции) и аргументы, отправляет по каналу, а результат — обратно. Поэтому:

  • функция должна импортироваться по имени — не лямбда и не вложенная;
  • аргументы — сериализуемые (не сокеты, не соединения с БД, не генераторы);
  • каждое копирование стоит времени: мелкие задачи с большими данными выполняются медленнее, чем последовательно.

Методы запуска:

  • fork — копия родителя с его памятью (copy-on-write): быстрый старт, глобальные данные доступны. Опасен, если в родителе уже были потоки: в ребёнке остаётся только один поток, а блокировки, которые держали другие, — захваченными навсегда.
  • spawn — новый интерпретатор, модуль импортируется заново. Медленнее, зато предсказуемо. Код запуска — под if __name__ == "__main__":, иначе дети рекурсивно запускают пул.
  • forkserver — компромисс: форк от чистого серверного процесса.

Обмен данными: multiprocessing.Queue, Pipe, Manager (прокси к объектам в процессе-сервере, медленно), shared_memory (Python 3.8) — общий буфер без копирования, удобно с NumPy.

Что хотят услышать

  • Отсутствие общей памяти и роль pickle.
  • Ограничения на функции и аргументы.
  • fork, spawn и их риски.

Частые ошибки

  • Запуск пула без if __name__ == "__main__".
  • Передача огромных объектов в каждую задачу.

Проверьте себя

Несколько верных вариантов. Подумайте, потом откройте ответ.

Показать варианты и ответ
  • ✓Аргументы и результаты сериализуются pickle и копируются
  • ✗Процессы делят общую память, поэтому аргументы не копируются и pickle не нужен
  • ✓Лямбды и локальные функции в процесс не передать
  • ✓При spawn нужна защита if __name__ == "__main__"

Разбор темы

Связанные вопросы

Партнёр платформы

Разбор собеседования с sotto

После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.

Разбор собеседования