FastAPI 不异步运行

FastAPI not behaving asynchronously

我可能没有正确理解 FastAPI 中的异步概念。

我同时从两个客户端访问以下应用程序的根端点。我希望 FastAPI 在执行开始时连续打印两次 Started

from fastapi import FastAPI
import asyncio

app = FastAPI()

@app.get("/")
async def read_root():
    print('Started')
    await asyncio.sleep(5)
    print('Finished')
    return {"Hello": "World"}

相反,我得到了以下内容,看起来非常非异步:

Started
Finished
INFO: ('127.0.0.1', 49655) - "GET / HTTP/1.1" 200
Started
Finished
INFO: ('127.0.0.1', 49655) - "GET / HTTP/1.1" 200

我错过了什么?

this github issue 中的演示来看,这可能不是由于 FastAPI,而是运行请求的客户端。

如何保证同时有多个请求?

您的代码没问题 - 尝试使用以下命令进行测试:

for n in {1..5}; do curl http://localhost:8000/ & ; done

您的浏览器可能正在缓存对同一 URL 的后续请求。

如果我没理解错的话,你试图合并从不同请求执行的打印。您可能应该将 print("started") 实现为协程并以这种方式使用它:

async def started():
    print("Started")

@app.get("/")
async def read_root():
    await started()
    await asyncio.sleep(5)
    print('Finished')
    return {"Hello": "World"}

但它不会如您所愿。如果您在数据库连接、身份验证和其他计算中使用困难的请求,尤其是对第三方的请求 API,您可以看到真正的异步。

祝你好运)

我用Chrome浏览器做了同样的实验,结果和最初报道的一样。来自两个独立 Chrome 浏览器的请求被一个接一个地处理(好像是串行的)。

@app.get("/test")
async def test():
    r = {"message": "Hello by /test api"}
    r['timestamp'] = datetime.datetime.utcnow()
    await asyncio.sleep(10)
    return r

2 个请求花了 20 秒(每个 10 秒)完成整个过程,这显然不是并发方式!

但是,当我按照答案中的建议尝试使用 curl 时,它是并行处理的 (!)

我上次用2个火狐浏览器做了实验,结果也是并行执行

最后,我从 FastAPI 的日志中找到了线索。 当我尝试使用 2 Chrome 个浏览器时,请求的来源 (ip:port) 被记录为相同

INFO:     10.10.62.106:54668 - "GET /test HTTP/1.1" 200 OK
INFO:     10.10.62.106:54668 - "GET /test HTTP/1.1" 200 OK

但是,如果我尝试使用 Firefox,则来源不同。

INFO:     10.10.62.106:54746 - "GET /test HTTP/1.1" 200 OK
INFO:     10.10.62.106:54748 - "GET /test HTTP/1.1" 200 OK

从上面的日志中,我可以得出结论,FastAPI(或前面的uvicorn)仅在源地址不同时才并行处理请求。

以上结论请大神补充。 谢谢

When you declare a path operation function with normal def instead of async def, it is run in an external threadpool that is then awaited, instead of being called directly (as it would block the server).

您可以在此 article 中找到更多详细信息,我在其中解释了在 FastAPI 中的何处使用异步。