Недавно я работал над проектом для домашних животных в python, используя колбу. Это простой pastebin с поддержкой синтаксиса на стороне сервера с помощью pygments. Поскольку это дорогостоящая задача, я делегировал выделение синтаксиса в очередь задач celery и в обработчике запросов я жду его завершения. Излишне говорить, что это не более чем облегчает использование ЦП другому работнику, потому что ожидание результата по-прежнему блокирует подключение к веб-серверу. Несмотря на то, что мои инстинкты говорили мне избегать преждевременной оптимизации, такой как чума, я все еще не мог помочь себе взглянуть на асинхронный процесс.
Асинхронный
Если вы в последнее время следовали за развитием веб-сайта python, вы наверняка видели, что асинхронная работа повсюду. То, что async делает, возвращает кооперативную многозадачность, то есть каждый "поток" решает, когда и где уступить другому. Этот неуправляемый процесс более эффективен, чем ОС-потоки, но все еще имеет свои недостатки. На данный момент, похоже, существуют два основных подхода:
- многозадачность стиля вызова/обратного вызова
- сопрограммы
Первый предоставляет concurrency через слабосвязанные компоненты, выполняемые в цикле событий. Хотя это более безопасно в отношении условий гонки и обеспечивает более согласованность, оно значительно менее интуитивно понятное и сложнее кодировать, чем превентивная многозадачность.
Другой - более традиционное решение, ближе к потоковому стилю программирования, причем программисту нужно только вручную переключать контекст. Несмотря на то, что он более подвержен условиям гонки и тупикам, он обеспечивает легкое решение для решения проблем.
В настоящее время большинство асинхронных операций выполняются на так называемых задачах с привязкой к IO, задачах, которые блокируют ожидания ввода или вывода. Обычно это достигается за счет использования функций, основанных на опросе и тайм-ауте, которые могут быть вызваны, и если они возвращаются отрицательно, контекст может быть переключен.
Несмотря на это имя, это может быть применено к задачам с привязкой к ЦП, которые могут быть делегированы другому работнику (потоку, процессу и т.д.), а затем без блокировки ждали выхода. В идеале эти задачи должны быть написаны с помощью асинхронного подхода, но реалистично это означало бы разделение кода на достаточно мелкие куски, чтобы не блокировать, предпочтительно без рассеяния переключателей контекста после каждой строки кода. Это особенно неудобно для существующих синхронных библиотек.
Из-за удобства, я решил использовать gevent для работы async и задавался вопросом, как нужно решать задачи, связанные с CPU, в среде асинхронного использования (используя фьючерсы, сельдерей и т.д.?).
Как использовать асинхронные модели выполнения (gentent в этом случае) с традиционными веб-фреймами, такими как фляжка? Каковы некоторые общепринятые решения этих проблем в python (фьючерсы, очереди задач)?
EDIT: Чтобы быть более конкретным - как использовать gevent с флягой и как бороться с задачами, связанными с CPU, в этом контексте?
EDIT2: Учитывая, что Python имеет GIL, который предотвращает оптимальное выполнение потокового кода, это оставляет только вариант многопроцессорности, по крайней мере, в моем случае. Это означает либо использование concurrent.futures, либо какой-либо другой внешней службы, связанной с обработкой (может открывать двери даже для языкового агностика). Что в данном случае было бы популярным или часто используемым решением с использованием gevent ( i.e. сельдерея)? - лучшие практики