bigywater.tech
Flask · 139

同步代码阻塞异步请求

协程里调用了一个阻塞函数会怎样?Flask 放到 ASGI 服务器上,sync 视图会不会拖慢整个服务?这篇用真实的 uvicorn、gunicorn 与两个 WSGI 到 ASGI 的适配器,把阻塞的影响范围量出来(还有一个我没预料到的串行结果)。

1620 ms
协程里 time.sleep(2) 时,uvicorn 上另一个请求被卡的时间
1609 ms
WsgiToAsgi 下任意慢请求进行中,另一个快请求的耗时(全部串行)
thread_sensitive=True
asgiref 的 sync_to_async 默认值,所有请求排到同一个线程

协程里阻塞

实测 · 本机执行输出
  在协程里调用 time.sleep(2)(阻塞)                           另一个请求用了    1620 ms
  await asyncio.sleep(2)(让出)                         另一个请求用了       2 ms
  await asyncio.to_thread(time.sleep, 2)(放到线程)       另一个请求用了       3 ms

上一篇:Async View 的执行边界;下一篇:Flask 与 ASGI。

gunicorn gthread 下

实测 · 本机执行输出
  async 视图里 time.sleep(2)                  另一个请求(/fast)用了     5 ms
  async 视图里 await asyncio.sleep(2)         另一个请求(/fast)用了     4 ms
  sync 视图里 time.sleep(2)                   另一个请求(/fast)用了     3 ms

WsgiToAsgi

实测 · 本机执行输出
  async 视图里 time.sleep(2)                  另一个请求(/fast)用了  1609 ms
  async 视图里 await asyncio.sleep(2)         另一个请求(/fast)用了  1599 ms
  sync 视图里 time.sleep(2)                   另一个请求(/fast)用了  1608 ms

这是本篇最出乎意料的结果:我原以为 sync 视图会被放进线程池并发执行,实测却是串行,所以去看了 asgiref 的源码确认原因。

a2wsgi

实测 · 本机执行输出
  async 视图里 time.sleep(2)                  另一个请求(/fast)用了     2 ms
  async 视图里 await asyncio.sleep(2)         另一个请求(/fast)用了     1 ms
  sync 视图里 time.sleep(2)                   另一个请求(/fast)用了     4 ms

发现阻塞

实测 · 本机执行输出
   ["Executing <Task finished name='Task-1' coro=<main() done, defined at <string>:4> result=None created at <stdlib>/asyncio/runners.py:110> took 0.510 seconds"]

分步演示

同步代码阻塞异步请求
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Python 3.14.7 / Flask 3.1.3 / Werkzeug 3.1.9 / Jinja2 3.1.6 / SQLAlchemy 2.1.1 / gunicorn 26.2.0(都装在自己的虚拟环境里);大多数实验用 Flask 的 test_client(直接调用 WSGI 应用,不经过网络),需要真实 HTTP 时另起 gunicorn 或开发服务器(端口 9600 以上,本机 127.0.0.1);计时用 time.perf_counter,数字每次运行会有小幅抖动。uvicorn 0.54.0、asgiref 3.12.1、a2wsgi 1.10.10、gunicorn gthread
    • 没有验证:hypercorn 等其它 ASGI 服务器、uvicorn 多 worker 下的行为、WsgiToAsgi 通过环境变量调整线程模型的可能、uvicorn 的 --limit-concurrency、a2wsgi 的线程池大小限制
    京ICP备2026067502号-1京公网安备11010502063487号