Многопроцессорная и потоковая обработка Python

Я пытаюсь понять преимущества многопроцессорность над резьбонарезной. Я знаю это многопроцессорность обходит глобальную блокировку интерпретатора, но какие еще преимущества есть, и может резьбонарезной не делать то же самое?

8 ответов


на threading модуль использует потоки,multiprocessing модуль использует процессы. Разница в том, что потоки работают в одном и том же пространстве памяти, а процессы имеют отдельную память. Это немного затрудняет совместное использование объектов между процессами с многопроцессорной обработкой. Поскольку потоки используют одну и ту же память, необходимо принять меры предосторожности или два потока будут записывать в одну и ту же память одновременно. Это то, для чего предназначен global interpreter lock.

процессы нереста немного медленнее, чем нерестовые нити. Когда они бегут, разница невелика.


вот некоторые плюсы/минусы я придумал.

Многопроцессорность

плюсы

  • отдельное пространство памяти
  • код обычно простой
  • использует преимущества нескольких процессоров и ядер
  • избегает ограничений GIL для cPython
  • устраняет большинство потребностей в примитивах синхронизации, если вы не используете общую память (вместо этого это больше модель связи для IPC)
  • ребенок процессы прерываются / убиваются
  • Python multiprocessing модуль включает в себя полезные абстракции с интерфейсом, очень нравится threading.Thread
  • обязательно с cPython для обработки с привязкой к процессору

минусы

  • IPC немного сложнее с большими накладными расходами (модель связи против общей памяти/объектов)
  • больший объем памяти след

резьбонарезной

плюсы

  • легкий-низкий объем памяти
  • общая память-облегчает доступ к состоянию из другого контекста
  • позволяет легко сделать отзывчивый UIs
  • модули расширения cPython C, которые правильно выпускают GIL, будут работать параллельно
  • отличный вариант для приложений, связанных с I/O

минусы

  • С CPython - в зависимости от GIL
  • не прерываемый/навахе
  • если не следовать моделью насоса очереди/сообщения команды (используя Queue module), то ручное использование примитивов синхронизации становится необходимостью (решения необходимы для детализации блокировки)
  • код, как правило, труднее понять и получить право - потенциал для условий гонки резко возрастает

работа Threading заключается в том, чтобы приложения были отзывчивыми. Предположим, у вас есть подключение к базе данных, и вам нужно ответить на ввод пользователя. Без потоковой передачи, если соединение с базой данных занято, приложение не сможет ответить пользователю. Разделив соединение с базой данных на отдельный поток, вы можете сделать приложение более отзывчивым. Кроме того, поскольку оба потока находятся в одном процессе, они могут получить доступ к одним и тем же структурам данных-хорошая производительность, а также гибкий разработка программного обеспечения.

обратите внимание, что из-за GIL приложение на самом деле не делает две вещи сразу, но то, что мы сделали, это поместить блокировку ресурсов в базе данных в отдельный поток, чтобы время процессора можно было переключаться между ним и взаимодействием пользователя. Время процессора распределяется между потоками.

Multiprocessing для времен когда вы действительно хотите больше чем одну вещь, котор нужно сделать в любой данный момент времени. Предположим, ваше приложение должно подключиться к 6 базам данных и выполнять комплексное матричное преобразование для каждого набора данных. Помещение каждого задания в отдельный поток может немного помочь, потому что, когда одно соединение простаивает, другое может получить некоторое время процессора, но обработка не будет выполняться параллельно, потому что GIL означает, что вы всегда используете ресурсы только одного процессора. Помещая каждое задание в процесс многопроцессорной обработки, каждый может работать на своем собственном процессоре и работать с полной эффективностью.


ключевым преимуществом является изоляция. Сбой процесса не приведет к сбою других процессов, в то время как сбой потока, вероятно, приведет к хаосу с другими потоками.


еще одна вещь, не упомянутая в том, что это зависит от того, какую ОС вы используете, когда речь идет о скорости. В Windows процессы являются дорогостоящими, поэтому потоки были бы лучше в windows, но в unix процессы быстрее, чем их варианты windows, поэтому использование процессов в unix намного безопаснее плюс быстро порождать.


другие ответы больше сосредоточены на аспекте многопоточности и многопроцессорности, но в Python Global Interpreter Lock (Гиль) должен быть принят во внимание. Когда больше числа (скажем k) потоков создаются, в основном они не увеличат производительность на k раз, так как он по-прежнему будет работать как однопоточное приложение. GIL-это глобальная блокировка, которая блокирует все и позволяет выполнять только один поток, используя только одно ядро. Производительность увеличивается в местах, где используются расширения C, такие как numpy, Network, I/O, где выполняется много фоновой работы и выпускается GIL.
когда резьбонарезной используется, существует только один поток уровня операционной системы, в то время как python создает псевдо-потоки, которые полностью управляются потоком, но по существу работают как один процесс. Вытеснение происходит между этими псевдо потоками. Если CPU работает на максимуме емкость, вы можете переключить к multiprocessing.
Теперь в случае автономных экземпляров выполнения вы можете вместо этого выбрать пул. Но в случае перекрытия данных, где вы можете захотеть, чтобы процессы общались, вы должны использовать multiprocessing.Process.


Как уже упоминалось в вопросе,Многопроцессорность в Python-единственный реальный способ достичь истинного параллелизма. многопоточность не может достичь этого, поскольку Гиль предотвращает параллельный запуск потоков.

как следствие, потоковая передача не всегда может быть полезна в Python, и на самом деле может даже привести к ухудшению производительности в зависимости от того, чего вы пытаетесь достичь. Например, если вы выполняете CPU-bound задача, такая как распаковка файлов gzip или 3D-рендеринг (что-нибудь интенсивное CPU), а затем резьба может фактически препятствовать вашей производительности, а не помочь. В таком случае вы захотите использовать Многопроцессорность Как только этот метод на самом деле работает параллельно и поможет распределить вес задачи. Там может быть некоторые накладные расходы на это, так как Многопроцессорность включает копирование памяти скрипта в каждый подпроцесс, что может вызвать проблемы для большего размера приложения.

, многопоточность становится полезным, когда ваша задача IO-bound. Например, если большая часть вашей задачи связана с ожиданием API-вызовы, вы должны использовать многопоточность потому что почему бы не запустить другой запрос в другом потоке, пока вы ждете, а не ваш процессор сидеть сложа руки.

TL; DR

  • многопоточность одновременно и используется для IO-bound задачи
  • Многопроцессорность достигает истинного параллелизма и используется для CPU-bound задачи

процесс может иметь несколько потоков. Эти потоки могут совместно использовать память и являются единицами выполнения в рамках процесса.

процессы выполняются на ЦП, поэтому потоки находятся под каждым процессом. Процессы-это отдельные сущности, которые работают независимо друг от друга. Если вы хотите обмениваться данными или состоянием между каждым процессом, вы можете использовать средство хранения памяти, такое как Cache(redis, memcache), Files или Database.