我们讲过@asynccontextmanager,参见Python 上下文管理器的使用
也讲过FastAPI,参见基于FastAPI框架的WebSocket服务器
再看看二者综合应用的框架(服务器端):
在FastAPI中,lifespan 事件用于管理应用的生命周期,包括启动和关闭时的逻辑。通过提供一个自定义的 lifespan 函数,你可以在应用启动前和执行某些初始化操作,以及在应用关闭前执行清理操作。
from contextlib import asynccontextmanager
from fastapi import FastAPI
from typing import Any, Dict
import asyncio
# 假设 CommunicationLayer 是一个处理通信的类
class CommunicationLayer:
def __init__(self):
# 初始化资源,例如建立连接、启动服务等
print("CommunicationLayer initialized")
async def launch(self, **param: Dict[str, Any]) -> Dict[str, Any]:
# 模拟启动过程,这里可以添加实际的启动逻辑
# 例如,根据参数启动服务或进程
print(f"Launching with parameters: {param}")
# 返回一个模拟的响应
return {"status": "success", "message": "Service launched"}
async def shutdown(self) -> None:
# 清理资源,例如关闭连接、停止服务等
print("CommunicationLayer shutdown")
# 异步上下文管理器,用于在应用生命周期中管理 communicator
@asynccontextmanager
async def lifespan(app: FastAPI):
global communicator
if communicator is None:
# 初始化 communicator
communicator = CommunicationLayer()
try:
yield
finally:
# 确保在应用关闭时关闭 communicator
await communicator.shutdown()
app = FastAPI(lifespan=lifespan)
communicator: CommunicationLayer = None
@app.post("/launch")
async def launch(param: Dict[str, Any]):
# 调用 communicator 的 launch 方法
return await communicator.launch(**param)
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=5050)
-
CommunicationLayer 类:这个类模拟了一个通信层,它包含初始化、启动和关闭的方法。
launch方法接收一个字典参数,并返回一个包含状态信息的字典。shutdown方法用于清理资源。 -
lifespan 异步上下文管理器:这个管理器在应用启动时初始化
communicator,并在应用关闭时确保communicator被正确关闭。使用try...finally结构来确保即使在发生异常时也能执行清理操作。 -
FastAPI 应用:使用
FastAPI创建应用,并通过lifespan参数传入自定义的生命周期管理器。 -
路由:定义了一个 POST 路由
/launch,它接收一个字典参数并调用communicator的launch方法。 -
运行应用:使用
uvicorn运行 FastAPI 应用。
async def lifespan(app: FastAPI)与app = FastAPI(lifespan=lifespan) ,看上去是循环定义(你中有我,我中有你),怎么回事?
在Python中,async def lifespan(app: FastAPI) 和 app = FastAPI(lifespan=lifespan) 之间的依赖关系并不是循环定义,而是应用配置和生命周期管理的一种常见模式。这里的关键在于理解函数定义(async def)和函数调用(或作为参数传递)之间的区别。
函数定义与调用
-
函数定义:
async def lifespan(app: FastAPI)定义了一个名为lifespan的异步函数,它接受一个FastAPI类型的参数app。这个定义本身并不执行任何代码,它只是声明了函数的存在和它的参数类型。 -
函数调用或作为参数传递:
app = FastAPI(lifespan=lifespan)是在创建FastAPI应用实例时,将lifespan函数作为参数传递给FastAPI类的构造函数。这里并没有调用lifespan函数(即没有执行await lifespan(...)),而只是将函数的引用传递给了FastAPI实例。
为什么这不是循环定义
-
定义阶段:在Python解释器读取代码时,它首先会识别并定义所有的函数、类和变量。在这个阶段,
lifespan函数被定义为一个可以接受的参数类型的异步函数。 -
实例化阶段:当执行到
app = FastAPI(lifespan=lifespan)时,FastAPI类的构造函数会接收lifespan函数的引用,并将其存储在内部,以便在适当的时候调用。此时,lifespan函数并没有被实际执行。 -
执行阶段:当FastAPI应用启动或关闭时,FastAPI框架会负责调用之前传递的
lifespan函数(实际上是调用你提供的异步上下文管理器),以执行相应的生命周期逻辑。
函数定义和实例化是两个独立的步骤,它们之间的依赖关系是通过参数传递来实现的,而不是通过相互调用或定义来实现的。



4888

被折叠的 条评论
为什么被折叠?



