1. CGI&WSGI&ASGI 到底是啥?python Flask 与Fastapi对比

492 阅读7分钟

image.png

1.CGI (Common Gateway Interface) 通用网关接口

CGI 是一种通用接口,它定义了Web服务器与后端应用程序(通常是CGI脚本)之间如何交互,特别是输入输出格式以及数据传递的方式。 CGI程序 =>每个请求启动一个新进程,效率低。

  1. CGI规范则是一个定义了Web服务器与应用程序之间的数据交互规范。它并不规定如何通过网络传输数据,而是定义了Web服务器和后端程序(如CGI脚本或Web应用)如何通过标准输入输出流(stdin/stdout)以及环境变量进行数据交换。

  2. 细节:

    • Web 服务器 → CGI 网关:Web 服务器接收到客户端的 HTTP 请求后,它会将请求内容转换为 CGI 需要的环境变量,并通过标准输入(stdin)将请求传递给 CGI 程序。Web 服务器与 CGI 网关之间的通信本质上是通过 标准输入输出(stdin, stdout)来完成的。

      • 例如,Web 服务器会把请求头信息(如请求路径、HTTP 方法)转化成环境变量传递给 CGI 程序。
    • CGI 网关 → Web 服务器:CGI 程序会根据请求处理逻辑执行操作(比如数据库查询、文件处理等),然后通过标准输出(stdout)将响应返回给 Web 服务器。

      • CGI 程序会生成 HTTP 响应头(如 Content-Type: text/html)和响应内容(如 HTML 页面),并通过标准输出传递回 Web 服务器。
  3. 实现了Web服务器网关接口的软件有:uWSGI(注意大小写)、uvicorn、gunicorn

**WSGI (Web Server Gateway Interface)

WSGI 是 Python Web 应用和 Web 服务器之间的标准接口,它比 CGI 高效,因为它不是每次请求都启动新的进程,而是保持一个 Web 服务器和 Python 应用之间的连接。WSGI 通过一个“中介”来传递请求和响应,所以它使得 Python 的 Web 框架(如 Flask、Django)能够与 Web 服务器(如 Nginx、Apache)协同工作。

通俗说法:WSGI 就像是 Web 服务器和 Python 应用之间的桥梁,它们通过这座桥来沟通。服务器把请求丢到桥上,应用在桥上做处理,然后把结果从桥上返回给服务器。不同于 CGI,它不需要每次请求都启动新的程序。

ASGI (Asynchronous Server Gateway Interface)

ASGI 是 WSGI 的升级版,它不仅支持传统的同步请求,还支持异步处理。这就意味着你可以在同一个 Web 应用中同时处理多个请求,而不需要等待一个请求完成才能处理下一个,这对于高并发应用(例如 WebSocket 或长连接)非常重要。

通俗说法:ASGI 是一个更“高效”的版本,它让 Web 应用能处理大量的同时请求,不会被一个请求阻塞。想象一下你在一个忙碌的餐厅工作,ASGI 就像是一个能够同时接待多个顾客、让每个顾客都得到及时服务的系统。



Q&A

  1. 自己实现一个socket 就可以实现 客户端与后端应用程序通信 那么就不需要cgi 所以cgi不是必需?

    1. CGI并不是必需的,它只是提供了一个标准化的方式来实现Web服务器与后端应用程序的交互。CGI是为Web服务器和应用程序交互定义的协议,它规定了如何传递请求参数、如何调用应用程序并返回结果。通过Socket,你可以绕过CGI协议,直接与后端应用程序建立通信。但是 直接通过Socket与后端应用程序进行通信,灵活性更高,但也需要更多的自定义工作。

    2. CGI的必要性:虽然绕过CGI协议,直接通过Socket与后端应用程序通信,但CGI协议在早期的Web开发中起到了很重要的作用,尤其是在Web服务器和后端应用程序之间实现标准化的接口时。CGI协议的作用主要体现在以下几点:

      • 标准化接口:CGI为Web服务器与后端应用程序提供了一种标准的通信方式,不同的Web服务器和后端应用程序都可以遵循这个标准进行交互。
      • Web服务器和应用程序解耦:Web服务器不需要直接知道应用程序的细节,只需要按照CGI协议调用应用程序即可。这使得Web服务器和应用程序之间的耦合度更低,更容易维护和替换。
      • 动态内容生成:CGI让Web服务器能够调用外部程序(如CGI脚本或Web应用),从而生成动态内容,而不只是返回静态页面。
  2. FastAPI 是使用ASGI(Asynchronous Server Gateway Interface)支持异步的,那么ASGI 的核心机制 是啥? 事件循环 + 协程

    1. 基于事件循环(Event Loop)
    2. 使用协程(Coroutine)进行任务切换
    3. I/O 操作时让出 CPU,继续处理其他请求
  3. 何为事件循环?

    📌 事件循环(Event Loop)

    ASGI 使用 Python 的 asyncio 事件循环 来管理任务。
    事件循环(Event Loop) 本质上是一个任务调度器,负责管理和执行协程(Coroutine)async / await 让 Python 支持协程,但协程本身不会自动运行,必须由事件循环来驱动它们。

    具体流程如下:

    • 执行任务
    • 遇到 I/O 操作时暂停(await)
    • 切换去执行其他任务
    • I/O 完成后恢复执行
  4. ASGI 服务器(Uvicorn)如何管理请求?

    以 FastAPI + Uvicorn 为例,服务器的请求处理流程如下

    1️⃣ 客户端发送请求
    2️⃣ Uvicorn 服务器接收请求,交给事件循环
    3️⃣ FastAPI 处理请求,遇到 I/O 操作(数据库查询)时,await 让出 CPU
    4️⃣ 事件循环继续处理其他请求
    5️⃣ I/O 操作完成后,FastAPI 继续执行并返回响应
    6️⃣ Uvicorn 发送响应给客户端

  5. 传统的 Flask + WSGI 工作方式是咋样的?

    1. 每个请求都会创建一个线程或进程 来执行视图函数。
    2. 函数必须执行完毕后,才能处理下一个请求(单线程时)。
    3. 遇到 I/O 操作(如数据库查询)时,会阻塞线程,直到 I/O 结束。

    Flask 之所以没有事件循环机制,主要是因为它基于 WSGI(Web Server Gateway Interface),而 WSGI 本身是 同步阻塞 的,无法像 ASGI 那样原生支持异步任务和事件循环。让我们深入看一下原因。

    • WSGI 是同步的:当请求到达 WSGI 服务器时,服务器会创建一个进程或线程来处理该请求。这个请求会被顺序处理,直到响应返回。

    • 阻塞执行:如果某个请求涉及到 I/O 操作(如数据库查询、文件读写、网络请求),整个处理过程就会阻塞,直到 I/O 完成,才能继续处理下一个请求。

    • 没有事件循环:在 WSGI 中,每个请求都是独立的,它们不能并发执行,也不能中断当前的处理过程去处理其他请求。

  6. async/await + 事件循环 = 非阻塞 I/O?

    当 Python 代码中使用 asyncawait

    1. 遇到 await 时,当前任务会暂停,并让出 CPU 给其他任务(不会阻塞线程)。
    2. 当 I/O 操作(如数据库查询)完成后,事件循环会恢复任务的执行
  7. 为啥说 flask和django自身携带的wsgi鸡肋 还需要使用uwsgi 或 gunicon?

    1. Flask 使用的是内置的 Werkzeug 服务器,Django 使用的是 runserver 命令启动的服务器)内置的服务器非常简单,主要功能是帮助开发者进行调试,不具备生产环境下所需的高并发和高性能特性。它们通常不支持多线程或多进程处理,也没有高级的负载均衡、连接池、请求队列等功能。
    2. Flask 和 Django 自带的 WSGI 服务器是同步的,这意味着每个请求都必须按顺序完成。对于高并发、IO密集型的应用(如实时聊天、文件上传下载等),内置的 WSGI 服务器无法有效利用异步编程优势。而 Gunicorn 和 uWSGI 等更强大的 WSGI 服务器支持并行的工作进程,可以更好地处理这些情况。