FastAPI 中可以有 10-30 秒的协程吗?
(就 FastApi 性能和良好实践而言)
因此客户端将有一个请求-响应开放 10-30 秒。
在客户端,我们使用 React.js,所以这对他们来说很好。
@app.get("/somepath")
async def read_item():
async with aiohttp.ClientSession() as session:
# some slow external API, 10-30 seconds
async with session.get(f"https://external.website.com/{some_api_key}/") as response:
response_json = await response.json()
return response_json
它会起作用的。所以这一边没有问题。
UX)对于大型工作来说非常有意义。如果用户了解为什么要等待并且在数据准备好/失败时有明确的响应,则无需进行太多优化。 如果需要,您可以使用 socketio 或 sse(服务器发送事件)实现完成百分比
Perf)您可以通过使用缓存大幅减少响应时间(从而提高性能和用户体验)。 (如果缓存时调用有意义) 它将减少响应时间并减少对服务器的并发请求数量。
FastAPI 中可以有 10-30 秒的协程吗?
首先,这不是一个FastAPI问题。
您预计会有多少个并行请求?很多?一些?您想限制同时运行的协程数量吗?默认情况下,asyncio 将使用尽可能多的资源。这可能是你想要的,也可能不是。如果您想限制同时运行的协程数量并对请求进行排队,您可能需要查看asyncio.Semaphore。
关于您的问题这是否是一个好的做法,这取决于您的工作流程。 Asyncio 是专门为此目的而创建的,用于长时间运行的后台任务,以在应用程序执行任务时释放应用程序。
现在,如果这是适合您的情况的最佳解决方案,那么如果没有清楚地了解您的应用程序正在做什么,就很难判断。如果用户关闭浏览器而请求仍在服务器中运行,会发生什么情况?用户不会得到有关其是否成功完成的反馈。你关心这个场景吗?如果这样做,您可以考虑使用队列并让 cronjob 在后台挑选要处理的内容。
我建议查看这个答案、这个答案和这个答案,了解如何在 FastAPI 中正确发出 HTTP 请求,以及如何重用一个AsyncClient
连接,而不是每次客户端调用端点时都会创建一个新会话。
上述答案的代码摘录
# ...
import httpx
@asynccontextmanager
async def lifespan(app: FastAPI):
# Initialise the Client on startup and add it to the state
async with httpx.AsyncClient() as client:
yield {'client': client}
# The Client closes on shutdown
app = FastAPI(lifespan=lifespan)
@app.get('/')
async def home(request: Request):
client = request.state.client
# ...
此外,如果外部 API 的响应非常大,您可以使用流式响应,而不是将 JSON 数据读入内存。请查看上面的答案,了解如何做到这一点,以及您还应该考虑缓存/存储从外部 API 返回的结果(请查看这个答案了解更多详细信息),如果它们不是客户端独有的并且也可以被其他人重用,这样您就可以避免对该 API 进行不必要的调用,从而节省资源、最大化性能并最小化响应时间。
此外,在处理从 FastAPI 后端返回 JSON 数据时,我建议查看以下答案,因为它们可能会帮助您优化代码:这个答案、这个答案以及这个答案 和这个答案。您可能会发现this和this也很有帮助。
最后,如果您发现响应需要花费太多时间才能返回给客户端,您可以考虑立即使用唯一的 id 回复用户,然后开始在后台处理他们的请求。然后,客户端可以使用该 id 来检查其请求的状态(例如,“待处理”、“处理中”或“完成”),如果请求已完成处理,他们可以请求结果(在您的情况下为 JSON 数据) .可以在这里和这里找到遵循类似方法的答案。您可能会发现这个答案也很有帮助。