многопроцессорность против многопоточности против asyncio в Python 3

114

Я обнаружил, что в Python 3.4 есть несколько разных библиотек для многопроцессорности / многопоточности: многопроцессорность vs многопоточность vs asyncio .

Но я не знаю, какой из них использовать, или какой из них «рекомендуется». Они делают то же самое или разные? Если да, то какой для чего? Я хочу написать программу, использующую многоядерность на моем компьютере. Но я не знаю, какую библиотеку мне следует изучить.

user3654650
источник
1
Может быть , я слишком глуп для AsyncIO помогает
Martin Thoma

Ответы:

84

Они предназначены для (немного) иных целей и / или требований. CPython (типичная основная реализация Python) по-прежнему имеет глобальную блокировку интерпретатора, поэтому многопоточное приложение (стандартный способ реализации параллельной обработки в настоящее время) неоптимально. Вот почему multiprocessing может быть предпочтительнее threading. Но не каждую проблему можно эффективно разделить на [почти независимые] части, поэтому может возникнуть необходимость в интенсивном межпроцессном взаимодействии. Вот почему multiprocessingне может быть предпочтительнее threadingвообще.

asyncio(этот метод доступен не только в Python, он также есть в других языках и / или фреймворках, например, Boost.ASIO ) - это метод для эффективной обработки большого количества операций ввода-вывода из многих одновременных источников без необходимости параллельного выполнения кода. . Так что это просто решение (действительно хорошее!) Для конкретной задачи, а не для параллельной обработки в целом.

user3159253
источник
7
Отметим, что хотя все три могут не достичь параллелизма, все они способны выполнять параллельные (неблокирующие) задачи.
sargas
72

[Быстрый ответ]

TL; DR

Сделать правильный выбор:

Мы рассмотрели самые популярные формы параллелизма. Но остается вопрос - когда выбрать какой? Это действительно зависит от вариантов использования. Исходя из моего опыта (и чтения), я склонен следовать этому псевдокоду:

if io_bound:
    if io_very_slow:
        print("Use Asyncio")
    else:
        print("Use Threads")
else:
    print("Multi Processing")
  • Ограничение ЦП => Многократная обработка
  • Ограничение ввода-вывода, быстрый ввод-вывод, ограниченное количество соединений => многопоточность
  • Ограничение ввода-вывода, медленный ввод-вывод, много соединений => Asyncio

Справка


[ ПРИМЕЧАНИЕ ]:

  • Если у вас есть метод длительного вызова (то есть метод, содержащий время сна или ленивый ввод-вывод), лучшим выбором является подход asyncio , Twisted или Tornado (методы сопрограммы), который работает с одним потоком в качестве параллелизма.
  • asyncio работает на Python3.4 и новее.
  • Tornado и Twisted готовы, начиная с Python2.7
  • uvloop это ультра быстрый asyncioцикл обработки событий ( uvloop делает asyncio2-4x быстрее).

[ОБНОВЛЕНИЕ (2019)]:

  • Japranto ( GitHub ) - это HTTP-сервер с очень быстрой конвейерной обработкой, основанный на uvloop .
Беньямин Джафари
источник
Итак, если у меня есть список URL-адресов для запроса, лучше использовать Asyncio ?
mingchau
1
@mingchau, Да, но имейте в виду, что вы можете использовать from, asyncioкогда используете из ожидаемых функций, requestбиблиотека не является ожидаемым методом, вместо этого вы можете использовать, например, aiohttpбиблиотеку или асинхронный запрос и т. д.
Беньямин Джафари,
пожалуйста, расширите на slowIO и fastIO, чтобы перейти на многопоточность или asyncio>?
qrtLs 04
1
Подскажите, пожалуйста, что такое io_very_slow
переменная
1
Ограничение ввода-вывода @variable означает, что ваша программа большую часть времени тратит на взаимодействие с медленным устройством, например сетевым подключением, жестким диском, принтером или циклом событий с временем ожидания. Таким образом, в режиме блокировки вы можете выбирать между потоковой передачей или асинхронностью, и если ваш ограничивающий раздел очень медленный, совместная многозадачность (asyncio) является лучшим выбором (т.е. предотвращение нехватки ресурсов, тупиков и условий гонки)
Беньямин Джафари
9

Это основная идея:

Это IO- BOUND? ---------> ИСПОЛЬЗОВАНИЕasyncio

ЭТО ЦП - ТЯЖЕЛЫЙ? -----> ИСПОЛЬЗОВАТЬmultiprocessing

ЕЩЕ? ----------------------> ИСПОЛЬЗОВАНИЕthreading

Поэтому в основном придерживайтесь потоковой передачи, если у вас нет проблем с вводом-выводом / процессором.

Фаршид
источник
4

В многопроцессорном режиме вы используете несколько процессоров для распределения вычислений. Поскольку каждый из процессоров работает параллельно, вы эффективно можете выполнять несколько задач одновременно. Вы хотели бы использовать многопроцессорность для задач, связанных с ЦП . Примером может быть попытка вычислить сумму всех элементов огромного списка. Если на вашем компьютере 8 ядер, вы можете «разрезать» список на 8 меньших списков и вычислить сумму каждого из этих списков отдельно для отдельного ядра, а затем просто сложить эти числа. Вы получите ~ 8-кратное ускорение, сделав это.

В (мульти) резьбывам не нужно несколько процессоров. Представьте себе программу, которая отправляет множество HTTP-запросов в Интернет. Если вы использовали однопоточную программу, она останавливала выполнение (блок) при каждом запросе, ожидала ответа, а затем продолжала после получения ответа. Проблема здесь в том, что ваш процессор на самом деле не работает, ожидая, пока какой-то внешний сервер выполнит эту работу; Тем временем он действительно мог бы проделать некоторую полезную работу! Исправление заключается в использовании потоков - вы можете создать множество из них, каждая из которых отвечает за запрос некоторого контента из Интернета. Хорошая вещь о потоках заключается в том, что даже если они работают на одном ЦП, ЦП время от времени «замораживает» выполнение одного потока и переходит к выполнению другого (это называется переключением контекста, и это происходит постоянно в недетерминированном режиме). интервалы). Итак, если ваша задача - использовать многопоточность.

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

Томаш Бартковяк
источник
Если у меня несколько потоков, а затем я начинаю получать ответы быстрее - и после ответов моя работа больше связана с процессором, - будет ли мой процесс использовать несколько ядер? То есть будет ли он замораживать потоки вместо использования нескольких ядер?
aspiring1
Не уверен, что понял вопрос. Вопрос в том, следует ли использовать несколько ядер, когда ответы становятся быстрее? Если это так - это зависит от того, насколько быстро будут ответы и сколько времени вы действительно тратите на их ожидание по сравнению с использованием процессора. Если вы тратите большую часть времени на выполнение задач, требующих интенсивного использования ЦП, было бы полезно распределить по нескольким ядрам (если возможно). И если вопрос, будет ли система самопроизвольно переключаться на параллельную обработку после «реализации» своей работы, зависит от процессора - я так не думаю - обычно вам нужно явно указать ей сделать это.
Томаш Бартковяк
Я думал о приложении чат-бота, в котором сообщения чат-бота пользователями отправляются на сервер, а ответы отправляются обратно сервером с использованием запроса POST? Как вы думаете, это более интенсивная задача для ЦП, поскольку отправленный и полученный ответ может быть json, но я сомневался - что произойдет, если пользователь потратит время, чтобы ввести свой ответ, является ли это примером медленного ввода-вывода? (пользователь отправляет ответ с опозданием)
aspiring1,