Как упоминалось в ответе @ Blusky: асинхронный API будет существовать в django 3.X. не раньше .
Если это не вариант, то ответ будет просто no .
Обратите внимание, что даже с django 3.X любой код django, который обращается к базе данных, будет не асинхронным, он должен быть выполнен в потоке (пуле потоков)
Celery предназначен для фоновых задач или отложенные задачи, но сельдерей никогда не вернет HTTP-ответ, поскольку он не получил HTTP-запрос, на который должен ответить. Celery также не поддерживает asyncio.
Возможно, вам придется подумать об изменении вашей архитектуры / реализации. Посмотрите на свою общую проблему и спросите себя, действительно ли вам нужен асинхронный API с Django.
Этот API предназначен для приложений браузера или для приложений между компьютерами?
Может ли ваш клиент использовать веб-сокетов и ждать ответа?
Не могли бы вы разделить блокирующую и неблокирующую части на стороне вашего сервера? Используйте django для всего, что не блокируется, для всего периодаi c / deferred (django + celelry) и реализуйте асинхронную часть с помощью плагинов веб-сервера или python кода ASGI или веб-сокетов.
Некоторые идеи
Используйте Django + nginx nchan (если ваш веб-сервер - сельдерей)
Ссылка на nchan: https://nchan.io/ ваш Вызов API создаст идентификатор задачи, запустит задачу с сельдереем, немедленно вернет идентификатор задачи или URL-адрес опроса.
URL-адрес опроса будет обрабатываться, например, через длинный канал опроса nchan. ваш клиент подключается к URL-адресу, соответствующему длинному каналу опроса nchan, и сельдерей деблокирует его всякий раз, когда ваша задача завершена (десятки закончились)
Используйте Django + сервер ASGI + один кодированный вручную просмотр и использование стратегии, аналогичной nginx nchan
Тот же logi c, как указано выше, но вы не используете nginx nchan, а реализуете его самостоятельно
Используйте сервер ASGI + неблокирующую структуру (или просто некоторые вручную закодированные представления ASGI) для всех блокирующих URL-адресов и Django для остальных.
Они могут обмениваться данными через базу данных, локально файлы или через локальные HTTP-запросы.
Просто продолжайте блокировать и запускайте на свой сервер достаточное количество рабочих процессов / потоков
Это, вероятно, худшее предложение, но если это просто для личного использования, и вы знаете, сколько запросов у вас будет параллельно, тогда просто убедитесь, что у вас достаточно Django воркеров, чтобы вы могли позволить себе блокировку. В этом случае вы бы заблокировали весь Django воркер для каждого низкого запроса.
Используйте веб-сокеты. например, с модулем каналов для Django
Веб-сокеты могут быть реализованы с более ранними версиями django (> = 2.2) с помощью модуля django каналов (pip install channels
) ( https://github.com/django/channels)
Вам нужен ASGI-сервер для сервера асинхронной части. Вы можете использовать, например, Daphne ot uvicorn (канал do c это довольно хорошо объясняет)
Приложение 2020-06-01: простой asyn c пример синхронного вызова django код
В следующем коде используется модуль starlette, поскольку он кажется довольно простым и маленьким
miniasyncio.py
import asyncio
import concurrent.futures
import os
import django
from starlette.applications import Starlette
from starlette.responses import Response
from starlette.routing import Route
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'pjt.settings')
django.setup()
from django_app.xxx import synchronous_func1
from django_app.xxx import synchronous_func2
executor = concurrent.futures.ThreadPoolExecutor(max_workers=2)
async def simple_slow(request):
""" simple function, that sleeps in an async matter """
await asyncio.sleep(5)
return Response('hello world')
async def call_slow_dj_funcs(request):
""" slow django code will be called in a thread pool """
loop = asyncio.get_running_loop()
future_func1 = executor.submit(synchronous_func1)
func1_result = future_func1.result()
future_func2 = executor.submit(synchronous_func2)
func2_result = future_func2.result()
response_txt = "OK"
return Response(response_txt, media_type="text/plain")
routes = [
Route("/simple", endpoint=simple_slow),
Route("/slow_dj_funcs", endpoint=call_slow_dj_funcs),
]
app = Starlette(debug=True, routes=routes)
вы можете, например, запустить это код с
pip install uvicorn
uvicorn --port 8002 miniasyncio:app
, затем на вашем веб-сервере перенаправьте эти c URL-адреса на uvicorn, а не на ваш django сервер приложений.