You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flask无原生异步支持?我的测试为何符合异步预期?

Flask异步能力的争议与实际场景适配疑问

测试背景与验证过程

看到不少博客及StackOverflow评论称Flask并非真正支持异步,于是编写测试脚本验证,已安装Flask[async]。

测试代码

import time
from flask import Flask, jsonify
import asyncio

app = Flask(__name__)

async def simulate_long_task():
    await asyncio.sleep(5)
    print("Task completed!")
    return "Task completed!"

async def simulate_long_task2():
    await asyncio.sleep(10)
    print("Task2 completed!")
    return "Task2 completed!"

@app.route('/test1')
async def test1():
    tasks = [simulate_long_task() for _ in range(2)]
    results = await asyncio.gather(*tasks)
    return jsonify({"message": results})

@app.route('/test2')
async def test2():
    s = time.time()
    tasks = [simulate_long_task2() for _ in range(2)]
    results = await asyncio.gather(*tasks)
    e =time.time()
    print(e-s)
    return jsonify({"message": results})

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

并发请求命令

curl 'http://127.0.0.1:5000/test1' & curl --location 'http://127.0.0.1:5000/test1' & curl --location 'http://127.0.0.1:5000/test1' &
curl 'http://127.0.0.1:5000/test2' & curl --location 'http://127.0.0.1:5000/test2' & curl --location 'http://127.0.0.1:5000/test2'

日志结果

Dload  Upload   Total   Spent    Left  Speed
100    50  100    50    0     0      9      0  0:00:05  0:00:05 --:--:--    13{"message":["Task completed!","Task completed!"]}

100    50  100    50    0     0      9      0  0:00:05  0:00:05 --:--:--    13{"message":["Task completed!","Task completed!"]}

100    50  100    50    0     0      9      0  0:00:05  0:00:05 --:--:--    13{"message":["Task completed!","Task completed!"]}

100    52  100    52    0     0      5      0  0:00:10  0:00:10 --:--:--    13{"message":["Task2 completed!","Task2 completed!"]}

100    52  100    52    0     0      5      0  0:00:10  0:00:10 --:--:--    13{"message":["Task2 completed!","Task2 completed!"]}

100    52  100    52    0     0      5      0  0:00:10  0:00:10 --:--:--    13{"message":["Task2 completed!","Task2 completed!"]}

结果与疑问

原本预期所有6个请求会在t=10时同时返回,但实际/test1的3个请求在t=5返回,/test2的在t=10返回,符合异步表现。但仍困惑Flask异步能力的争议点,想了解:

  • 测试中忽略的核心问题
  • Flask异步不适配的场景
  • 何时需要改用FastAPI
  • 针对部署机器学习模型多用户请求端点的需求,该如何选择

解答与分析

1. Flask异步的本质局限

Flask的异步支持是基于WSGI协议的兼容层实现,并非原生异步框架(如FastAPI基于ASGI协议)。WSGI本身是同步协议,Flask通过在WSGI服务器中嵌入asyncio事件循环来支持异步视图,但核心的请求处理模型仍受限于WSGI的同步特性:

  • 默认的Werkzeug服务器是单线程(调试模式为多线程),单个请求内的协程能被事件循环调度,但遇到CPU密集型任务(如机器学习推理)时,协程会阻塞整个事件循环,导致其他请求等待。
  • 生产级WSGI服务器(如Gunicorn)即使开启多进程/多线程,每个进程/线程的事件循环独立,无法实现跨请求的协程调度,和传统同步Flask的并发模型无本质区别。

2. 测试中忽略的核心问题:跨请求并发能力

你的测试仅验证了单个请求内的协程并发,但Flask的异步无法解决跨请求的阻塞问题。例如,若有一个请求在执行CPU密集型的模型推理,在WSGI模型下,该请求会占用当前进程/线程,其他请求必须等待资源释放。而原生ASGI框架(如FastAPI)可在单进程单线程下通过协程调度处理数千个并发请求,只要任务是IO密集型或能正确释放GIL。

3. Flask异步不适配的场景

  • 高并发IO密集型场景:如大量需要等待外部API、数据库查询的请求,Flask的异步无法充分利用协程优势,WSGI的线程/进程池会成为瓶颈。
  • CPU密集型异步任务:机器学习推理多为CPU/GPU密集型,即使写成async函数,也无法在Flask的异步模型中实现真正并发,GIL会阻塞事件循环,导致其他请求等待。
  • 长连接场景:如WebSocket、Server-Sent Events等,Flask异步对这类场景支持有限,而FastAPI原生支持ASGI的长连接特性。

4. 何时改用FastAPI

当遇到以下情况时,建议切换到FastAPI:

  • 需要处理高并发多用户请求:机器学习端点若需同时处理数十上百个请求,FastAPI的ASGI模型能用更少资源处理更多并发。
  • 涉及长连接或实时交互:如需要推送模型推理进度的WebSocket场景。
  • 需利用原生异步生态:如使用异步数据库驱动、异步HTTP客户端等,FastAPI能更好整合这些工具。
  • 追求便捷的生产特性:FastAPI自带OpenAPI文档、类型提示、依赖注入等特性,对机器学习端点的调试和维护更友好。

针对机器学习部署需求的建议

  • 若模型推理为GPU加速(如TensorFlow/PyTorch的GPU推理),GIL影响较小,Flask+多进程服务器(如Gunicorn+Uvicorn作为WSGI worker)也能处理一定并发,但FastAPI的异步模型仍能更高效管理请求队列。
  • 若为CPU密集型推理且并发量较高,FastAPI配合Uvicorn(ASGI服务器)能通过协程调度,在单个进程中处理更多请求,减少资源占用。
  • 此外,FastAPI的请求验证、权限控制等特性,能更方便地处理多用户请求的参数校验、身份认证等,适合生产环境部署。

内容的提问来源于stack exchange,提问作者Moein Hasani

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 00:40:58