Многопроцессорность или многопоточность в питоне?

У меня есть приложение Python, которое захватывает коллекцию данных, и для каждого фрагмента данных в этой коллекции он выполняет задачу. Задача занимает некоторое время, поскольку существует задержка. Из-за этой задержки я не хочу, чтобы каждый фрагмент данных впоследствии выполнял задачу, я хочу, чтобы все они выполнялись параллельно. Должен ли я использовать многопроцессорность? или нарезка резьбы для этой операции?

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

8 ответов

Если вы действительно ограничены в вычислениях, использование многопроцессорного модуля, вероятно, является самым легким решением (с точки зрения как потребления памяти, так и сложности реализации).

Если вы связаны с вводом / выводом, использование потокового модуля обычно даст вам хорошие результаты. Убедитесь, что вы используете поточно-ориентированное хранилище (например, очередь) для передачи данных вашим потокам. Или же передайте им один кусок данных, который является уникальным для них, когда они появляются.

PyPy ориентирован на производительность. Он имеет ряд функций, которые могут помочь в обработке вычислений. Они также поддерживают программную транзакционную память, хотя это еще не качество продукции. Обещание состоит в том, что вы можете использовать более простые параллельные или параллельные механизмы, чем многопроцессорность (что имеет некоторые неудобные требования).

Stackless Python также хорошая идея. У Stackless есть проблемы с переносимостью, как указано выше. Разгрузившаяся Ласточка была многообещающей, но теперь несуществующей. Pyston - еще одна (незавершенная) реализация Python, ориентированная на скорость. Это подход, отличный от PyPy, который может привести к лучшему (или просто другому) ускорению.

Задачи выполняются последовательно, но у вас есть иллюзия, что они работают параллельно. Задачи хороши, когда вы используете для файлового или подключенного ввода-вывода и потому, что они легкие.

Многопроцессорность с пулом может быть правильным решением для вас, потому что процессы выполняются параллельно, поэтому очень хорошо работают с интенсивными вычислениями, потому что каждый процесс выполняется в одном процессоре (или ядре).

Настройка многопроцессорности может быть очень простой:

from multiprocessing import Pool

def worker(input_item):
    output = do_some_work()
    return output

pool = Pool() # it make one process for each CPU (or core) of your PC. Use "Pool(4)" to force to use 4 processes, for example.
list_of_results = pool.map(worker, input_list) # Launch all automatically

Для небольших коллекций данных просто создайте подпроцесс с помощью subprocess.Popen.

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

Когда подпроцессы завершены (или истекло время ожидания), вы просто объединяете выходные файлы.

Очень просто.

Вы могли бы рассмотреть заглянуть в Stackless Python. Если у вас есть контроль над функцией, которая занимает много времени, вы можете просто бросить stackless.schedule() s там (говорит уступить следующей сопрограмме), или вы можете установить Stackless в вытесняющую многозадачность.

В Stackless у вас нет потоков, а есть тасклеты или гринлеты, которые, по сути, очень легкие. Он прекрасно работает в том смысле, что есть довольно хорошая структура с очень небольшими настройками для запуска многозадачности.

Однако Stackless препятствует переносимости, поскольку вам необходимо заменить несколько стандартных библиотек Python - Stackless устраняет зависимость от стека C. Он очень переносим, ​​если у следующего пользователя также установлен Stackless, но это случается редко.

Использование модели потоков CPython не даст вам никакого улучшения производительности, потому что потоки фактически не выполняются параллельно, из-за способа обработки сборки мусора. Многопроцессорность позволила бы параллельное выполнение. Очевидно, что в этом случае вам нужно иметь несколько доступных ядер для выполнения параллельных заданий.

В этом связанном вопросе доступно гораздо больше информации.

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

Вы можете посмотреть на Twisted. Он предназначен для асинхронных сетевых задач.

IronPython имеет настоящую многопоточность, в отличие от CPython и GIL. Поэтому, в зависимости от того, что вы делаете, стоит посмотреть. Но, похоже, ваш вариант использования лучше подходит для многопроцессорного модуля.

Парню, который рекомендует Python без стеков, я не эксперт в этом, но мне кажется, что он говорит о программной "многопоточности", которая на самом деле не параллельна вообще (все еще работает в одном физическом потоке, поэтому не может масштабироваться до несколько ядер.) Это просто альтернативный способ структурировать асинхронное (но все же однопоточное, непараллельное) приложение.

Другие вопросы по тегам