FastAPI+Uvicorn多请求并行处理问题咨询及解决方案
FastAPI多进程运行相关问题
背景与代码
我是Python开发新手,但有.NET开发背景。编写了一个简单的FastAPI应用:
from fastapi import FastAPI import time import logging import asyncio import random app = FastAPI() r = random.randint(1, 100) logging.basicConfig(level="INFO", format='%(levelname)s | %(asctime)s | %(name)s | %(message)s') logging.info(f"Starting app {r}") @app.get("/") async def long_operation(): logging.info(f"Starting long operation {r}") await asyncio.sleep(1) time.sleep(4) # 我知道这会阻塞且端点标记为async,但我的代码中确实存在阻塞请求 return r
使用如下命令启动应用:
uvicorn "main:app" --workers 4
启动后应用创建了4个进程实例,日志如下:
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit) INFO: Started parent process [22112] INFO | 2023-05-11 12:32:43,544 | root | Starting app 17 INFO: Started server process [10180] INFO: Waiting for application startup. INFO: Application startup complete. INFO | 2023-05-11 12:32:43,579 | root | Starting app 58 INFO: Started server process [29592] INFO: Waiting for application startup. INFO: Application startup complete. INFO | 2023-05-11 12:32:43,587 | root | Starting app 12 INFO: Started server process [7296] INFO: Waiting for application startup. INFO: Application startup complete. INFO | 2023-05-11 12:32:43,605 | root | Starting app 29 INFO: Started server process [15208] INFO: Waiting for application startup. INFO: Application startup complete.
打开3个浏览器标签页并行发送请求,日志如下:
INFO | 2023-05-11 12:32:50,770 | root | Starting long operation 29 INFO: 127.0.0.1:55031 - "GET / HTTP/1.1" 200 OK INFO | 2023-05-11 12:32:55,774 | root | Starting long operation 29 INFO: 127.0.0.1:55031 - "GET / HTTP/1.1" 200 OK INFO | 2023-05-11 12:33:00,772 | root | Starting long operation 29 INFO: 127.0.0.1:55031 - "GET / HTTP/1.1" 200 OK INFO | 2023-05-11 12:33:05,770 | root | Starting long operation 29 INFO: 127.0.0.1:55031 - "GET / HTTP/1.1" 200 OK INFO | 2023-05-11 12:33:10,790 | root | Starting long operation 29 INFO: 127.0.0.1:55031 - "GET / HTTP/1.1" 200 OK INFO | 2023-05-11 12:33:15,779 | root | Starting long operation 29 INFO: 127.0.0.1:55031 - "GET / HTTP/1.1" 200 OK INFO | 2023-05-11 12:33:20,799 | root | Starting long operation 29 INFO: 127.0.0.1:55031 - "GET / HTTP/1.1" 200 OK INFO | 2023-05-11 12:33:25,814 | root | Starting long operation 29 INFO: 127.0.0.1:55031 - "GET / HTTP/1.1" 200 OK INFO | 2023-05-11 12:33:30,856 | root | Starting long operation 29 INFO: 127.0.0.1:55031 - "GET / HTTP/1.1" 200 OK
观察结果
- 仅1个进程在处理请求,其余进程未参与(多次测试均如此);
- 已成功创建4个不同的实例。
疑问
- 为何仅一个进程工作,其余进程不处理请求?
- 能否实现内存缓存?
- 能否用单个进程并行处理一定数量的请求?
- 该现象是否与我在Windows系统上测试有关?
更新+解决方案
核心问题是def/async def的行为(容易混淆)。原本尝试通过多进程解决线程阻塞问题,但测试时仅一个进程工作,原因是使用单个浏览器的多个标签页测试。改用JMeter测试后,所有进程均正常被使用。
但多进程并非最优解,更好的方式是解除单进程中的线程阻塞:
- 起初使用
asyncio.loop.run_in_executor方案,因为依赖的外部库只有同步IO函数; - 后来找到了该函数的异步版本,最终通过使用正确的异步库解决问题。
感谢大家的帮助。
内容的提问来源于stack exchange,提问作者Anubis
相关产品推荐
相关产品推荐

