ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

九、Django3的ASGI

2022-07-01 23:02:33  阅读:210  来源: 互联网

标签:异步 WSGI Web ASGI Django3 web 服务器


九、Django3的ASGI

9.1、Web应用程序和web服务器

Web应用程序(Web)是一种能完成web业务逻辑,能让用户基于web浏览器访问的应用程序,它可以是一个实现http请求和响应功能的函数或者类,也可以是Django、Flask、sanic等这样的web框架,当然也可以是其他语言的web程序或web框架。

Web服务器(Web Server)是一种运行于网站后台(物理服务器)的软件。Web服务器主要用于提供网页浏览或文件下载服务,它可以向浏览器等Web客户端提供html网页文档,也可以提供其他类型的可展示文档,让客户端用户浏览;还可以提供数据文件下载等。目前世界上最主流的Web服务器有 Nginx 、Apache、IIS、tomcat。

问:Web服务器和Web应用程序的区别?
答:Web应用程序主要是完成web应用的业务逻辑的处理,Web服务器则主要是应对外部请求的接收、响应和转发。
    需要使用web服务器启动运行,web应用程序才能被用户访问到。
    而django框架中,我们之所以只有一个web应用程序就跑起来了,是因为我们在终端执行了一个命令,python manage.py runserver。这个命令启动了django框架中内置提供的测试web服务器。

9.2、网关接口

网关接口(Gateway Interface,GI)就是一种为了实现加载动态脚本而运行在Web服务器和Web应用程序中的通信接口,也可以理解为一份协议/规范。只有Web服务器和Web应用程序都实现了网关接口规范以后,双方的通信才能顺利完成。常见的网关接口协议:CGI,FastCGI,WSGI,ASGI。

image-20210608222947398

(1)CGI

CGI(Common Gateway Inteface): 字面意思就是通用网关接口,

它是外部应用程序与Web服务器之间的接口标准

意思就是它用来规定一个程序该如何与web服务器程序之间通信从而可以让这个程序跑在web服务器上。当然,CGI 只是一个很基本的协议,在现代常见的服务器结构中基本已经没有了它的身影,更多的则是它的扩展和更新。

FastCGI: CGI的一个扩展, 提升了性能,废除了 CGI fork-and-execute (来一个请求 fork 一个新进程处理,处理完再把进程 kill 掉)的工作方式,转而使用一种长生存期的方法,减少了进程消耗,提升了性能。

这里 FastCGI 就应用于前端 server(nginx)与后端 server(uWSGI)的通信中,制定规范等等,让前后端服务器可以顺利理解双方都在说什么(当然 uWSGI 本身并不用 FastCGI, 它有另外的协议)

(2)WSGI

WSGI(Python Web Server GateWay Interface):它是用在 python web 框架编写的应用程序与后端服务器之间的规范(本例就是 Django 和 uWSGI 之间),让你写的应用程序可以与后端服务器顺利通信。在 WSGI 出现之前你不得不专门为某个后端服务器而写特定的 API,并且无法更换后端服务器,而 WSGI 就是一种统一规范, 所有使用 WSGI 的服务器都可以运行使用 WSGI 规范的 web 框架,反之亦然。

WSGI和ASGI,都是基于Python设计的网关接口(Gateway Interface,GI)。

image-20210608223815714

Web服务器网关接口(Python Web Server Gateway Interface,WSGI),是Python为了解决Web服务器端与客户端之间的通信基于CGI标准而设计的。实现了WSGI协议的web服务器有:uWSGI、uvicorn、gunicorn。像django框架一般开发中就不会使用runserver来运行,而是采用上面实现了WSGI协议的web服务器来运行。

django中运行runserver命令时,其实内部就启动了wsgiref模块作为web服务器运行的。wsgiref是python内置的一个简单地遵循了wsgi接口规范的web服务器程序。

from wsgiref.simple_server import make_server
# application 由wsgi服务器调用、函数对http请求与响应的封装、使得Python专注与HTML
# environ http 请求 (dist)
# start_response 响应 (function)
def application(environ, start_response):
    # 请求
    if environ['REQUEST_METHOD'] == 'GET' and environ['PATH_INFO'] == '/':
        # 响应
        start_response('200 OK', [('Content-Type', 'text/html')])
        return [b'<h1>hi, python!</h1>']

if __name__ == '__main__':
    # 启动服务器 | 这个服务器负责与 wsgi 接口的 application 函数对接数据
    httpd = make_server('127.0.0.1', 8000, application)

    # 监听请求
    httpd.serve_forever()
    
    
# 1. 监听8000端口,
# 2. 把http请求根据WSGI协议将其转换到applcation中的environ参数, 然后调用application函数.
# 3. wsgiref会把application函数提供的响应头设置转换为http协议的响应头,
# 4. 把application的返回(return)作为响应体, 根据http协议,生成响应, 返回给浏览器.

开发中,我们一般使用uWSGI或者Gunicorn作为web服务器运行django。

(3)uWSGI

uWSGI 是一个快速的,自我驱动的,对开发者和系统管理员友好的应用容器服务器,用于接收前端服务器转发的动态请求并处理后发给 web 应用程序。完全由 C 编写,实现了WSGI协议,uwsgi,http等协议。注意:uwsgi 协议是一个 uWSGI服务器自有的协议,用于定义传输信息的类型,常用于uWSGI服务器与其他网络服务器的数据通信中。

uwsgi: 是uWSGI服务器实现的独有的协议, 网上没有明确的说明这个协议是用在哪里的,我个人认为它是用于前端服务器与 uwsgi 的通信规范,相当于 FastCGI的作用。

img

在这里插入图片描述

img

9.3、关于ASGI

9.3.1、历史趣谈

2019 年 12 月,Django3.0 发布,它具有一个有趣的新特性——支持 ASGI 服务器。

2003 年,诸如Zope、Quixote之类的各式各样的 Python Web 框架都附带了自己的 Web 服务器,或者拥有自己的本地接口来与流行的网络服务器(如 Apache)进行通信。

成为一名 Python Web 开发人员意味着要全身心投入到一个完整的技术栈中,但是如果需要另一个框架时,则必须重新学习所有内容。可以想象到这会导致碎片化。PEP 333,即 Python Web 服务器网关接口 v1.0,尝试通过定义一个被称为 WSGI(Web Server Gateway Interface)的简单标准接口来解决这个问题。它的卓越之处在于它的简单性。

WSGI 如此流行,以至它不仅被诸如 Django 和 Pylons 之类的大型 Web 框架所采用,还被诸如 Bottle 之类的微框架所采用。

为什么有ASGI的出现

如果我们对 WSGI 非常满意的话,为什么还要提出 ASGI 呢?如果仔细检查网络请求的整个处理流程,那么答案就非常明显了。您可以查看 在Django中网络请求如何工作 的动画。请注意,在数据库查询之后且响应发送之前,框架是如何等待的。这就是同步处理的缺点。

坦白说,直到 2009 年 Node.js 出现时,这种缺陷才变得明显或紧迫。Node.js 的创建者 Ryan Dahl 受到 C10K 问题的困扰,即为什么像 Apache 这样的流行 Web 服务器无法处理 10,000 个或更多的并发连接(给定典型的 Web 服务器硬件,内存将会耗尽)。他思考到 “查询数据库时,软件在做什么?”。

当然,答案是什么也没有发生。它正在等待数据库的响应。Ryan 认为网络服务器根本不应该去等待 I / O 活动。换言之,它应该切换为处理其他请求,并在较慢的活动完成时能得到通知。

越来越明显的是,基于异步事件的架构是解决多种并发问题的正确方法。也许这就是为什么 Python 的创建者 Guido 亲自为 Tulip 项目提供语言级别支持的原因,这个项目后来成为了 asyncio 模块。最终,Python 3.7 添加了新的关键字 async 和 await ,用于支持异步事件循环。这不仅对如何编写 Python 代码而且对代码执行也具有重大意义。

Python 的两个世界

虽然使用 Python 编写异步代码非常简单,在函数定义前添加 async 关键字,但是您必须非常小心,不要打破一个重要的规则:不要随意混合使用同步代码和异步代码。

这是因为同步代码可以阻止异步代码中的事件循环。这种情况会使您的应用程序陷入停顿。正如 Andrew Goodwin 所写:这会将您的代码分为两个世界——具有不同库和调用风格的“同步代码”和“异步代码”。

回到 WSGI,这意味着我们无法编写异步可调用对象并将其嵌入。WSGI 是为同步世界编写的。我们将需要一种新的机制来调用异步代码。但是,如果每个人都编写自己的一套机制,我们将回到最初的不兼容地狱。因此,对于异步代码,我们需要一个类似于 WSGI 的新标准。因此,ASGI 诞生了。

ASGI 还有其他一些目的。但是在此之前,让我们看一下两种类似的 Web 应用程序“Hello World”,它们分别采用 WSGI 和 ASGI 风格。

与 WSGI 一样,ASGI 可调用对象可以一个接一个地链接在一起,以处理 Web 请求(以及其他协议请求),即链式调用。实际上,ASGI 是 WSGI 的超集且可以调用 WSGI 可调用对象。ASGI 还支持长时间轮询,慢速流媒体和其他响应类型,而无需侧向加载,从而可以加快响应速度。

因此,ASGI 引入了构建异步 Web 界面和处理双向协议的新方式。客户端或服务器端都无需等待对方进行通信——这可以随时异步发生。现存且以同步代码编写的基于 WSGI 的 Web 框架将不支持这种事件驱动的工作方式。

Django 演变

同时,想将所有这些异步优势带给 Django 面临一个重大的问题 —— 所有 Django 代码都是以同步风格编写的。如果我们需要编写任何异步代码,那么需要一个采用异步风格编写的整个 Django 框架的副本。换句话说,创建两个 Django 世界。

好吧,不要惊慌——我们可能不必编写一个完整的副本,因为有聪明的方式可以在两个世界之间重用一些代码。正如领导 Django Async 项目的安德鲁·戈德温(Andrew Godwin)正确地指出的那样,“这是 Django 历史上最大规模的修订之一”。一个雄心勃勃的项目采用异步风格重新实现 ORM、请求处理程序(request handler)、模板渲染器(Template renderer)等组件。这将分阶段进行,并在多个版本中完成。如下是安德鲁的预想(这不视为已提交的时间表):

  • Django 3.0-ASGI 服务器
  • Django 3.1-异步视图
  • Django 3.2 / 4.0-异步 ORM

您可能正在考虑其余的组件,例如模板渲染、表单和缓存等。它们可能仍然保持同步或者其异步实现会纳入到将来的技术路线中。但是以上是 Django 在异步世界中发展的关键里程碑。

9.3.2、asgi的使用

ASGI,是构建于WSGI接口规范之上的异步服务器网关接口,是WSGI的延伸和扩展。

A指的是Async,异步的意思。
协议,规范 支持的请求协议(常见,未列全) 同步/异步 支持的框架
CGI HTTP   CGI程序
WSGI HTTP 同步 django3.0以前,Flask1.0
ASGI HTTP,HTTP2,WebSocket等 同步/异步 FastAPI,Quart,Sanic,Tornado,django3.0以后,flask2.0

在 Python3.5 之后增加 async/await 特性之后简化了协程操作以后,异步编程变得异常火爆,越来越多开发者投入异步的怀抱。

3.0版本以前,django所提供的所有内部功能都是基于同步编程的。所以,在以往django开发中,针对网络请求,数据库读取等IO操作形成的阻塞,往往会导致项目运行性能的下降。虽然等待I/O操作数微秒时,但是随着流量的增加和操作的频率上升,这一点点的阻塞就会导致整个项目运作的缓慢。而如果换成异步就不会有任何阻塞,还可以同时处理其他任务,从而以较低的延迟处理更多的请求。所以在目前python开发中,越来越多的框架开始支持了异步编程。所以,3.0版本以后,django开始支持异步编程,可以让开发者在django中使用python第三方异步模块,推出了asgi异步web服务器。3.1版本推出了异步视图,当然,目前django的异步编程还不够完善,django中只有极少的功能是支持了异步操作。

image-20210608235013829

Uvicorn 是一个快速的 ASGI 服务器,Uvicorn 是基于 uvloop 和 httptools 构建的,是 Python 异步生态中重要的一员。

Uvicorn 当前支持 HTTP / 1.1 和 WebSockets,将来计划支持HTTP / 2。

文档:https://www.uvicorn.org/

安装uvicorn

pip install uvicorn

项目根目录下,运行django项目

# uvicorn 主应用目录名.asgi:application --reload
uvicorn homework.asgi:application --reload

开发中一般使用gunicorn来管理uvicorn。所以可以一并安装

pip install gunicorn

运行

# gunicorn -w 4 主应用目录名.asgi:application -k uvicorn.workers.UvicornWorker --reload
gunicorn -w 4 homework.asgi:application -k uvicorn.workers.UvicornWorker --reload

 

标签:异步,WSGI,Web,ASGI,Django3,web,服务器
来源: https://www.cnblogs.com/xiaohaoge/p/16436171.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有