关于django:一代版本一代神利用Docker在Win10系统极速体验Django31真实异步Async任务

38次阅读

共计 4382 个字符,预计需要花费 11 分钟才能阅读完成。

原文转载自「刘悦的技术博客」https://v3u.cn/a_id_177

就在去年 (2019 年),Django 官网公布 3.0 版本,内核降级发表反对 Asgi,这一重磅音讯让有数后盾研发人员欢呼雀跃,弹冠相庆。如获至宝之下,小伙伴们兴奋的开箱试用,后果却让人大跌眼镜:非但说好的外部集成 Websocket 没有呈现,就连原生的异步通信性能也只是个壳子,外部并未实现,很显著的换汤不换药,这让不少人转身投入了 FastAPI 的怀抱。不过一年之后,明天 8 月,Django3.1 版本捷足先登,这个新版本终于一代封神,不仅反对原生的异步视图,同时也反对异步中间件,显著整了个大活。

本次咱们利用 Docker 制作一款基于 Django3.1.1 的我的项目镜像,理论体验一下 Django 原生异步的魅力。

首先在宿主机装置新版 Django

pip install Django3.1.1

新建一个我的项目,名字为 django31

django-admin.py startproject django31 .

进入我的项目目录能够发现,相熟的入口文件 mange.py 曾经隐没不见,新增了 asgi.py 文件用来启动我的项目,这里咱们应用异步服务器 uvicorn 来启动新版 Django,而 uvicorn 对 windows 零碎反对不够敌对,所以应用 Docker 来构建一个运行镜像,简略不便,进入 django31 目录,新建 Dockerfile:

FROM python:3.7  
WORKDIR /Project/django31  
  
COPY requirements.txt ./  
RUN pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple  
  
COPY . .  
ENV LANG C.UTF-8  
WORKDIR /Project  
CMD ["uvicorn", "django31.asgi:application","--host","0.0.0.0"]

这里须要留神一点,Docker 每创立一个容器,会在 iptables 中增加一个规定,每个容器都会在本机 127.17.X.X 范畴内调配一个地址,容器绑定的主机端口会映射到本机的 127.17.X.X 的容器抛出端口上。所以容器外部的我的项目绑定的 ip 不能是 127.0.0.1,要绑定为 0.0.0.0,这样绑定后容器外部 app 的理论 ip 由 Docker 主动调配,所以这里 uvicorn 启动参数须要用 host 强制绑定为 0.0.0.0。

随后在我的项目中创立依赖文件 requirements.txt:

django==3.1.1  
uvicorn  
httpx

开始编译镜像文件:

docker build -t 'django31' .

编译胜利后大略 1g 左右

liuyue:django31 liuyue$ docker images  
REPOSITORY                  TAG                   IMAGE ID            CREATED             SIZE  
django31                    latest                e8afbbbb9305        30 minutes ago      919MB

而后咱们来启动我的项目:

docker run -it --rm -p 8000:8000 django31

后盾显示启动顺利,绑定在容器内的 0.0.0.0:

liuyue:django31 liuyue$ docker run -it --rm -p 8000:8000 django31  
INFO:     Started server process [1]  
INFO:     Waiting for application startup.  
INFO:     ASGI 'lifespan' protocol appears unsupported.  
INFO:     Application startup complete.  
INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)

浏览器拜访:http://localhost:8000

相熟的小火箭又腾飞了,接下来咱们来编写第一个异步视图 views.py

from django.http import HttpResponse  
async def index(request):  
    return HttpResponse("异步视图")

批改一下路由文件 urls.py

from django.contrib import admin  
from django.urls import path  
from django31.views import index  
  
urlpatterns = [path('admin/', admin.site.urls),  
    path("", index)  
]

从新编译镜像:

docker build -t 'django31' .  
docker run -it --rm -p 8000:8000 django31

拜访 http://localhost:8000

没有问题,还记得去年咱们已经应用 Siege 对 Django2.0 版本进行压力测试吗?当初咱们再来测一下

siege -c150 -t60S -v -b 127.0.0.1:8000

150 个并发继续一分钟,看看新版 Django 的抗压能力怎么样:

liuyue:~ liuyue$ siege -c150 -t60S -v -b 127.0.0.1:8000  
  
{    "transactions":                   10517,  
    "availability":                  100.00,  
    "elapsed_time":                   59.70,  
    "data_transferred":                0.12,  
    "response_time":                0.84,  
    "transaction_rate":              176.16,  
    "throughput":                    0.00,  
    "concurrency":                  148.58,  
    "successful_transactions":           10517,  
    "failed_transactions":                   0,  
    "longest_transaction":                1.13,  
    "shortest_transaction":                0.45  
}  
liuyue:~ liuyue$

从测试后果看,整体性能尽管没有质的进步,然而也还算是差强人意,乞丐级主机在 uvicorn 的加持下单机 200 个左右并发还是能抗住的。

接下来咱们来体验一下真正的技术,Django 内置的原生异步工作,别离同步和异步两种形式应用 httpx 来申请接口,办法中人为的阻塞 10 秒钟:



from django.http import HttpResponse  
  
import asyncio  
from time import sleep  
import httpx

#异步申请  
async def http_call_async():  
    for num in range(10):  
        await asyncio.sleep(1)  
        print(num)  
    async with httpx.AsyncClient() as client:  
        r = await client.get("https://v3u.cn")  
        print(r)  
  
#同步申请  
def http_call_sync():  
    for num in range(10):  
        sleep(1)  
        print(num)  
    r = httpx.get("https://v3u.cn")  
    print(r)

再别离通过同步和异步视图进行调用:

async def async_view(request):  
    loop = asyncio.get_event_loop()  
    loop.create_task(http_call_async())  
    return HttpResponse("非阻塞视图")  
  
  
def sync_view(request):  
    http_call_sync()  
    return HttpResponse("阻塞视图")

批改路由:

from django.contrib import admin  
from django.urls import path  
from django31.views import index, async_view, sync_view  
  
urlpatterns = [path('admin/', admin.site.urls),  
    path("", index),  
    path("async/", async_view),  
    path("sync/", sync_view),  
]

从新编译:

docker build -t 'django31' .  
docker run -it --rm -p 8000:8000 django31

拜访 http://localhost:8000/sync/ 看看同步的效率

很显著过程中阻塞了 10 秒,而后咱们才等到页面后果:

再来试试不一样的,拜访 http://localhost:8000/async/

16 毫秒,忽视阻塞,霎时响应。

通过动图咱们能够发现,后端还在执行阻塞工作,然而前段曾经通过异步多路复用将申请工作后果返回至浏览器了。

尽管这曾经很不错了,然而稍有遗憾的是,目前 Django 内置的 ORM 还是同步机制,也就是说当咱们读写数据库的时候还是阻塞状态,此时的场景就是异步视图内塞入了同步操作,这该怎么办呢?能够应用内置的 sync_to_async 办法进行转化:

from asgiref.sync import sync_to_async  
async def async_with_sync_view(request):  
    loop = asyncio.get_event_loop()  
    async_function = sync_to_async(http_call_sync)  
    loop.create_task(async_function())  
    return HttpResponse("(via sync_to_async)")

由此可见,Django3.1 在异步层面真的开始秀操作了,这就带来另外一个问题,既然原生异步工作曾经做得这么牛逼了,咱们到底还有没有必要应用 Celery?

其实对于 Django 的异步视图只是提供了相似于工作或音讯队列的性能,但性能上并没有 Celery 弱小。如果你正在应用 (或者正在思考)Django3.1,并且想做一些简略的事件 (并且不关怀可靠性),异步视图是一种疾速、简略地实现这个工作的好办法。如果你须要执行重得多的、长期运行的后盾过程,你还是要应用 Celery。

简而言之,Django3.1 的异步工作目前仅仅是解决 Celery 过重的一个简化计划而已。

结语:如果咱们说,新世纪以来在 Python 在 Web 开发界有什么成就,无疑的,咱们应该说,Django 和 Flask 是两个颠扑不破的巨石重镇,没有了它们,Python 的 web 开发史上便要黯然失光,Django 作为第一 web 开发框架,要文档有文档,要性能有性能,腰斩对手于马下,麻利开发利器。Django3.1 的公布好像把咱们又拉回到了 Django 一统江湖的年代,那个美妙的时代,让有数人午夜梦回。

原文转载自「刘悦的技术博客」https://v3u.cn/a_id_177

正文完
 0