Ответ вслух Senior GIL, потоки и процессы обновлено

Как распараллелить обработку в Python-сервисе

Вопрос

Нужно обработать 1 млн изображений: скачать по URL, уменьшить, загрузить в S3. Как вы это распараллелите на Python?

Попробуйте сами

Ответьте вслух за 2 минуты, как на собесе. Потом сверьтесь с тезисами: что прозвучало, а что нет.

Показать ответ и разбор

Коротко

Образцовый ответ: «Сначала разделю работу по характеру нагрузки. Скачивание и загрузка в S3 это ожидание сети, ресайз это процессор.

Что должно прозвучать в ответе

  • Разделить этапы: скачивание и загрузка I/O-bound, ресайз CPU-bound

  • I/O: asyncio или пул потоков с ограничением параллелизма

  • CPU: пул процессов по числу ядер или библиотека, отпускающая GIL

  • Очередь между этапами, обратное давление, батчи

  • Масштабирование на несколько машин через очередь задач

  • Ретраи, идемпотентность, учёт прогресса

Что могут спросить следом

  • Как ограничить число одновременных запросов к S3?
  • Что будет, если процесс упадёт на середине?

Разбор

Образцовый ответ: «Сначала разделю работу по характеру нагрузки. Скачивание и загрузка в S3 это ожидание сети, ресайз это процессор. Для сетевых этапов возьму asyncio с HTTP-клиентом и семафором на, скажем, 100 одновременных запросов, либо пул потоков, если библиотеки синхронные. Ресайз отдам в ProcessPoolExecutor по числу ядер; Pillow частично отпускает GIL, но процессы надёжнее. Этапы свяжу очередями с ограниченным размером, чтобы скачивание не убегало вперёд и не забивало память. Миллион файлов на одной машине долго, поэтому вынесу задачи в брокер, Celery или аналог, и запущу несколько воркеров на разных машинах. Каждую задачу делаю идемпотентной: ключ в S3 детерминирован, повторная обработка безопасна. Плюс ретраи на временные ошибки сети, учёт обработанных id, чтобы после падения продолжить, и метрики скорости и ошибок».

Ответьте сами, а не прочитайте

В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.