bigywater.tech
Flask · 138

Async View 的执行边界

async 视图到底在哪里执行?请求上下文还在吗?视图返回后后台任务会怎样?全局的异步锁能用吗?这篇逐项验证 async 视图的边界。

新事件循环
每个请求都有自己的事件循环,请求结束就关闭
bound to a different event loop
模块级 asyncio.Event 与 Lock 在第二个请求里的报错
not run
视图返回后 create_task 启动的任务 1 秒后的状态

执行线程

实测 · 本机执行输出
  sync 视图: {'main': True, 'thread': 'MainThread'}
  async 视图: {'main': False, 'thread': 'ThreadPoolExecutor-1_0'}

上一篇:Flask Async View;下一篇:同步代码阻塞异步请求。

可用的上下文

实测 · 本机执行输出
  app_name           b
  contextvar         set in before_request
  g_value            set in before_request
  has_request_context True
  request_path       /ctx
  session_x          1

响应之后的任务

实测 · 本机执行输出
  create_task 之后立刻返回响应,1 秒后任务状态: not run
  await 了任务再返回: responded after task | 任务状态: finished

全局 asyncio 对象

实测 · 本机执行输出
  GET /global-event  → 200 'timed out waiting (event not set)'
  GET /global-event  → 500 '<!doctype html>\n<html lang=en>\n<title>500 Internal Server Error</title'
  GET /global-lock   → 200 'lock ok'
  GET /global-lock   → 500 '<!doctype html>\n<html lang=en>\n<title>500 Internal Server Error</title'
  再请求一次 /global-event(让异常传播出来)→ RuntimeError: <asyncio.locks.Event object at 0x108b22660 [unset]> is bound to a different event loop
  再请求一次 /global-lock(让异常传播出来)→ RuntimeError: <asyncio.locks.Lock object at 0x108b227b0 [locked]> is bound to a different event loop

线程里的上下文

实测 · 本机执行输出
  asyncio.to_thread 里直接 has_request_context(): True
  再用 copy_current_request_context 包装后读 request.path: /copy-ctx
  自己 new 的 threading.Thread 里 has_request_context(): False
  to_thread 的工作线程名: asyncio_0

分步演示

Async View 执行边界
本步的对象

    本文用到的工具与边界

    • 本机 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,数字每次运行会有小幅抖动。asgiref 3.12.1
    • 没有验证:在 ASGI 服务器下同样的行为(第 140 篇)、异步数据库连接池与 HTTP 客户端的正确生命周期管理、Flask 的 ensure_sync 与 async 错误处理器、取消(客户端断开)时协程收到的异常
    京ICP备2026067502号-1京公网安备11010502063487号