在我的Django异步视图中,任务未被执行。

huangapple go评论51阅读模式
英文:

The task in my Django asynchronous view is not executed

问题

Django 异步视图可以立即响应,而任务是异步运行的,但事实上任务无法继续。

async def task_async():
print('任务开始')
await asyncio.sleep(2)
print('任务运行成功')


async def view_async(request):
print('异步开始')
loop = asyncio.get_event_loop()
loop.create_task(task_async())
print('返回')
return HttpResponse("非阻塞的 HTTP 请求")


我期望任务在 HTTP 响应返回后继续运行,但结果是:

异步开始
返回
任务开始


使用 uvicron 是可以的,但是 manage.py 和 daphne project.asgi:application 则不行,这让我感到困惑,uvicron 的结果如下:

异步开始
返回
任务开始
任务运行成功


<details>
<summary>英文:</summary>

Django asynchronous views can respond immediately, while tasks run asynchronously,but in fact the task cannot continue.

async def task_async():
print('task begin')
await asyncio.sleep(2)
print('task run success')


async def view_async(request):
print('async begin')
loop = asyncio.get_event_loop()
loop.create_task(task_async())
print('return')
return HttpResponse("Non-blocking HTTP request")


I expect the task to continue running after the http response returns, but the result is:

async begin
return
task begin


Using uvicron is ok, but manage.py and  daphne project.asgi:application are not, this is where i am confused, the result of uvicron ars as follows:

async begin
return
task begin
task run success


</details>


# 答案1
**得分**: 1

默认的 `manage.py runserver` 命令运行一个 [`wsgiref.simple_server`](https://docs.python.org/3/library/wsgiref.html#module-wsgiref.simple_server) 服务器,该服务器从你的 `settings.py` 中提供 `WSGI_APPLICATION`。对于异步视图的调用被包装在 `async_to_sync` 中,在单独的线程中执行,并且没有持久的事件循环。

在开发中要使用 ASGI,需要安装 Daphne 服务器,它带有自己的 `runserver` 命令:

```bash
$ pip install daphne

编辑你的 settings.py

INSTALLED_APPS = [
    "daphne",  # <---
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    ...
]

...

ASGI_APPLICATION = "yourproject.asgi.application"  # <---

现在,python manage.py runserver 应该表现得像你所期望的那样。

我必须补充的是,Django 中的异步支持主要用于改善 I/O 绑定代码的性能,对于后台任务,更好的做法是使用 ChannelsCelery 或其他任务运行器。


英文:

The default manage.py runserver command runs a wsgiref.simple_server which serves a WSGI_APPLICATION from your settings.py. Calls to async views are wrapped in async_to_sync, executed in a separate thread and don't have a persistent event loop.

To use ASGI during development, install Daphne server, which comes with its own runserver command:

$ pip install daphne

Edit your settings.py:

INSTALLED_APPS = [
    &quot;daphne&quot;,  # &lt;---
    &quot;django.contrib.admin&quot;,
    &quot;django.contrib.auth&quot;,
    &quot;django.contrib.contenttypes&quot;,
    ...
]

...

ASGI_APPLICATION = &quot;yourproject.asgi.application&quot;  # &lt;---

Now, python manage.py runserver should behave like you've expected.

I must add that async support in Django is primarily intended to improve performance for I/O bound code and for background tasks the better practice would be to use Channels, Celery or another task runner.


EDIT: screenshots of both runserver and standalone daphne working with the example view from the question:

在我的Django异步视图中,任务未被执行。

在我的Django异步视图中,任务未被执行。

huangapple
  • 本文由 发表于 2023年2月19日 13:32:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/75498197.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定