下面是一些示例代码来演示这个问题:
import asyncio
import datetime
import time
import uvicorn
from fastapi import FastAPI
from starlette.responses import PlainTextResponse
app = FastAPI()
@app.get(path="/sync")
def get_sync():
print(f"sync: {datetime.datetime.now()}: Before sleep")
time.sleep(5)
print(f"sync: {datetime.datetime.now()}: After sleep")
return PlainTextResponse(content=f"sync: {datetime.datetime.now()}: Hello, World!")
@app.get(path="/async")
async def get_async():
print(f"async: {datetime.datetime.now()}: Before sleep")
await asyncio.sleep(5)
print(f"async: {datetime.datetime.now()}: After sleep")
return PlainTextResponse(content=f"async: {datetime.datetime.now()}: Hello, World!")
if __name__ == "__main__":
uvicorn.run(app=app, host="0.0.0.0", port=1911)
- 选择以上任意端点:
GET /sync
或GET /async
- 从两个不同的web浏览器选项卡调用端点(或使用cURL等)来创建两个并行请求
- 第一个请求阻塞第二个请求
我期望GET /sync
在线程池上运行。我期望GET /async
使用一些asyncio魔法。
我不能使用多个工作者。是否有一个解决方案,允许与单个工作线程并发请求?
供参考:我使用Python 3.7(64位/Win10)和最新版本的FastAPI + unvicorn。
从浏览器调用web端点将被阻塞(在客户端),因为它正在等待响应。为了正确地测试它,您需要异步调用它。例如,您可以使用单独的python脚本
import asyncio
import aiohttp
from aiohttp import ClientSession
async def call_async(session: ClientSession, url: str):
async with session.get(url) as result:
async def main():
async with aiohttp.ClientSession() as session:
url = 'https://localhost:5000/async' # change port
tasks = [call_async(session, url) for i in range(5)]
for finished_task in asyncio.as_completed(tasks):
print(await finished_task)
asyncio.run(main())