异步启停 aiohttp 服务程序

异步启停 aiohttp 服务程序

目录

  • [异步启停 aiohttp 服务程序](#异步启停 aiohttp 服务程序)
    • 一、引言
    • [二、aiohttp 服务端的基本用法](#二、aiohttp 服务端的基本用法)
    • [三、异步启停 Application 实例](#三、异步启停 Application 实例)

一、引言

aiohttp 是一个很好的 python 异步 web 库,可以用它建立高效的 web 服务端和客户端。它支持 http 协议,也支持 websocket 长连接。

一般情况下,开发 web 服务端时,我们会用 run_app 启动一个 aiohttp 的 Application,run_app 是阻塞运行的,直到整个程序的退出才关闭。

如果需要在一个线程的序运行中按需启停服务,或者是启动多个服务,就需要异步地的启动 Application,本文根据 aiohttp 的官方文档,对这个问题进行一些探讨。

有关异步启停和优雅关闭服务方面可供参考的官方文档网址如下:https://docs.aiohttp.org/en/stable/web_advanced.html#aiohttp-web-graceful-shutdown

二、aiohttp 服务端的基本用法

aiohttp 官网给出服务端的基本用法 。启动一个服务端须经历以下几个步骤:

1. 生成一个 aiohttp.web.Application 实例;

2. 编写一个或多个服务程序;

3. 将服务程序加入 Application 实例的路由(route);

4. 运行 Application 实例,启动服务。

下面的程序简单演示了 aiohttp 的基本用法:

python 复制代码
from aiohttp import web


# 2. 编写服务程序;
async def hello(request):
    return web.Response(text="Hello, world")

# 1. 生成 Application 实例;
app = web.Application()
# 3. 将服务加入 Application 的路由;
app.add_routes([web.get('/', hello)])
# 4. 启动服务。
web.run_app(app, host="127.0.0.1", port=8888)

运行这个程序,在本机打开浏览器,地址栏输入:127.0.0.1:8888。浏览器就会显示服务返回的"Hello world"字符串。

上述程序中,还可以用 route 装饰形成路由表,启动前直接将路由表加入 Application 实例:

python 复制代码
from aiohttp import web

# 定义路由表
routes = web.RouteTableDef()


# 定义路由表中的应用服务程序
@routes.get('/')
async def hello(request):
    return web.Response(text="Hello, world")


app = web.Application()
# 将路由表加入 Application 实例
app.add_routes(routes)
web.run_app(app, host="127.0.0.1", port=8888)

三、异步启停 Application 实例

上述 web.run_app 方法是阻塞运行的。它无法在一个线程中启动多个不同 url 的服务,也不方便服务的随时启动和停止。为此,aiohttp 提供了 runner 类,可以异步启停多个服务。

上述使用 web.run_app 方法运行 Application 的程序略加修改,就可以使用 runner 类启动:

python 复制代码
from aiohttp import web
import asyncio


async def hello(request):
    return web.Response(text="Hello, world")


# 由于 runner 的设置和 site 的启动是异步方法,所以它们必须处于一个异步函数中
async def run_server():
    app = web.Application()
    app.add_routes([web.get('/', hello)])
    runner = web.AppRunner(app)
    await runner.setup()
    site = web.TCPSite(runner, 'localhost', 8080)
    # 异步启动 site,下面的语句不阻塞
    await site.start()
	# 如果需要启停一个或多个服务,可以将代码放在这个位置,但要保证 run_server 不退出,
	# 否则所有的服务都退出了。
	
	# 这是模拟的代码,保证 run_server 不退出。
    while True:
        await asyncio.sleep(3600)

# 启动程序的同步代码
asyncio.run(run_server())

它的运行结果和和前面的程序是一样的,但与之相比,这个程序做了如下修改和补充:

1. 用已经生成的 Application 实例建立一个 web.AppRunner 的实例(runner);

2. 用 setup 方法对 runner 进行设置;

3. 建立一个 web.TCPSite 实例,并用 start 方法启动这个实例。

如果将 run_server 方法的最后两行(while True: 和 await asyncio ...两行)改为:asyncio.sleep(20),再运行这个程序就会发现:运行20秒后程序就退出了。

实际应用程序中,服务的退出不应该如此粗暴,关于优雅地退出服务的内容,可以参见官网文档

相关推荐
红色石头本尊10 分钟前
1-umi-前端工程化搭建
前端
真夜17 分钟前
关于对echart盒子设置百分比读取的宽高没有撑开盒子解决方案
前端
楠木68531 分钟前
RAG 资料库 Demo 完整开发流程
前端·ai编程
肠胃炎42 分钟前
挂载方式部署项目
服务器·前端·nginx
像我这样帅的人丶你还1 小时前
使用 Next.js + Prisma + MySQL 开发全栈项目
前端
FPGA小迷弟1 小时前
FPGA 时序约束基础:从时钟定义到输入输出延迟的完整设置
前端·学习·fpga开发·verilog·fpga
毛骗导演1 小时前
@tencent-weixin/openclaw-weixin 插件深度解析(四):API 协议与数据流设计
前端·架构
毛骗导演1 小时前
@tencent-weixin/openclaw-weixin 插件深度解析(二):消息处理系统架构
前端·架构
IT_陈寒2 小时前
深入理解JavaScript:核心原理与最佳实践
前端·人工智能·后端
MrGud2 小时前
Cesium中的坐标系及其转换
前端·cesium