Подтвердить что ты не робот

Python async и задачи, связанные с процессором?

Недавно я работал над проектом для домашних животных в python, используя колбу. Это простой pastebin с поддержкой синтаксиса на стороне сервера с помощью pygments. Поскольку это дорогостоящая задача, я делегировал выделение синтаксиса в очередь задач celery и в обработчике запросов я жду его завершения. Излишне говорить, что это не более чем облегчает использование ЦП другому работнику, потому что ожидание результата по-прежнему блокирует подключение к веб-серверу. Несмотря на то, что мои инстинкты говорили мне избегать преждевременной оптимизации, такой как чума, я все еще не мог помочь себе взглянуть на асинхронный процесс.

Асинхронный

Если вы в последнее время следовали за развитием веб-сайта python, вы наверняка видели, что асинхронная работа повсюду. То, что async делает, возвращает кооперативную многозадачность, то есть каждый "поток" решает, когда и где уступить другому. Этот неуправляемый процесс более эффективен, чем ОС-потоки, но все еще имеет свои недостатки. На данный момент, похоже, существуют два основных подхода:

  • многозадачность стиля вызова/обратного вызова
  • сопрограммы

Первый предоставляет concurrency через слабосвязанные компоненты, выполняемые в цикле событий. Хотя это более безопасно в отношении условий гонки и обеспечивает более согласованность, оно значительно менее интуитивно понятное и сложнее кодировать, чем превентивная многозадачность.

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

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

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


Из-за удобства, я решил использовать gevent для работы async и задавался вопросом, как нужно решать задачи, связанные с CPU, в среде асинхронного использования (используя фьючерсы, сельдерей и т.д.?).

Как использовать асинхронные модели выполнения (gentent в этом случае) с традиционными веб-фреймами, такими как фляжка? Каковы некоторые общепринятые решения этих проблем в python (фьючерсы, очереди задач)?

EDIT: Чтобы быть более конкретным - как использовать gevent с флягой и как бороться с задачами, связанными с CPU, в этом контексте?

EDIT2: Учитывая, что Python имеет GIL, который предотвращает оптимальное выполнение потокового кода, это оставляет только вариант многопроцессорности, по крайней мере, в моем случае. Это означает либо использование concurrent.futures, либо какой-либо другой внешней службы, связанной с обработкой (может открывать двери даже для языкового агностика). Что в данном случае было бы популярным или часто используемым решением с использованием gevent ( i.e. сельдерея)? - лучшие практики

4b9b3361

Ответ 1

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

from threading import Thread

def send_async_email(msg):
    mail.send(msg)

def send_email(subject, sender, recipients, text_body, html_body):
    msg = Message(subject, sender = sender, recipients = recipients)
    msg.body = text_body
    msg.html = html_body
    thr = Thread(target = send_async_email, args = [msg])
    thr.start()

ЕСЛИ вам нужно что-то более сложное, возможно, вам может быть полезной библиотека Flask-Celery или Multiprocessing с "Pool".

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

Я имею в виду, если вы пытаетесь повысить эффективность крупного мирового веб-сайта, я бы рекомендовал создавать приложения на С++ для работы с интенсивным процессором, а затем использовать Flask-celery или Pool для запуска этого процесса. (это то, что делает YouTube при смешивании С++ и Python)

Ответ 2

Как просто использовать ThreadPool и Queue? Затем вы можете обрабатывать свои вещи в отдельном потоке синхронно, и вам не придется беспокоиться о блокировке вообще. Ну, Python, в первую очередь, не подходит для задач с привязкой к процессору, поэтому вы также должны думать о нерестах подпроцессов.