Как использовать функции блокировки с asyncio - PullRequest
0 голосов
/ 25 мая 2018

Я использую django ORM в проекте (вне django).Мой рабочий процесс

  1. выбор объектов с помощью ORM django и
  2. , а затем отправка его в очередь сообщений с использованием asyncio lib

Проблема в том, что вы можетене вызывайте блокирующие функции в асинхронной среде, и вы не можете использовать async / await в блокирующей среде.

Я предложил 2 решения:

  1. Вся программа должнабыть асинхроннымИ используйте loop.run_in_executor для вызова функций блокировки при необходимости.

  2. Вся программа должна быть синхронизирована.И используйте asyncio.run() (Python 3.7) для вызова необходимых асинхронных функций.

Я не могу решить, какой из них лучше подходит.

Я знаю Подобный вопрос был задан ранее.Мой вопрос: есть ли общее правило при попытке объединить блокирующий и неблокирующий код?

1 Ответ

0 голосов
/ 25 мая 2018

Учитывая выбор между этими двумя, я определенно рекомендовал бы подход № 1.

# 2 имеет недостаток, который вы упускаете из-за большого количества функций asyncio, разделяя вызовы asyncio на отдельное небольшое событие.цикл проходит.Например, вы не можете создать «фоновую» задачу, выполнение которой охватывает несколько вызовов asyncio.run(), и такие вещи могут быть очень полезны для регистрации, мониторинга или тайм-аута.(Использование asyncio.run также может быть проблемой производительности, поскольку при каждом вызове создается новый цикл обработки событий, но это можно исправить, переключившись на run_until_complete.)

Но есть и третий вариант:

  • Создать отдельный поток, который выполняет только loop.run_forever() и ожидает выполнения работы.Остальная часть программы состоит из обычного кода блокировки, который может запросить что-то от asyncio, используя asyncio.run_coroutine_threadsafe().Эта функция не блокируется;он немедленно возвращает concurrent.futures.Future, который вы можете передать, а метод result() автоматически ожидает получения результата.Он поддерживает дополнительные функции, такие как ожидание параллельного завершения нескольких экземпляров с использованием wait, итератор as_completed и т. Д.

ЭтоПодход ИМХО сочетает в себе лучшие характеристики двух вариантов из вопроса.Он оставляет блокирующий код по-настоящему блокирующим, при этом ему по-прежнему разрешается ждать, когда что-то произойдет, порождать потоки и т. Д., Не заставляя использовать async def и run_in_executor по всем направлениям.В то же время части asyncio могут быть написаны с использованием лучших практик asyncio с длительным циклом обработки событий, обслуживающим всю программу.Вам просто нужно быть осторожным, чтобы all взаимодействовал с циклом событий от остальной части приложения (даже для вызова чего-то столь простого, как loop.stop), которое должно быть выполнено с помощью loop.call_soon_threadsafe и asyncio.run_coroutine_threadsafe.

...