bigywater.tech
Flask · 148

长轮询

长轮询在 Flask 里怎么写?延迟比短轮询好多少?为什么它特别吃线程?断线重连会不会丢消息?这篇用真实的 gunicorn gthread 与 gevent worker,把这些量出来。

1.0 → 554 ms
送达延迟中位数:长轮询与每秒短轮询
2520 vs 5 ms
8 个轮询在等待时,普通请求的耗时:gthread 8 线程与 gevent
since
用来在重连时不丢消息的游标参数

长轮询的延迟

实测 · 本机执行输出
  长轮询:送达延迟中位数 1.0 ms,最大 2.2 ms
  每秒短轮询:送达延迟中位数 554 ms,最大 985 ms

上一篇:请求超时;下一篇:Server-Sent Events。

占用线程

实测 · 本机执行输出
  gthread × 1 个 worker × 8 线程    8 个轮询在等待时,/ping 用了 2520 ms
  gevent × 1 个 worker            8 个轮询在等待时,/ping 用了 5 ms
  gevent 同时挂着 300 个等待中的轮询,/ping 用了 5 ms,整个 gunicorn(含 master)内存约 88 MB

游标与重连

实测 · 本机执行输出
  客户端上次收到 id=1,断开期间又发布了 2、3;重新带 since=1 轮询 → 拿到的 id: [2, 3]
  之后没有新消息:since=3 轮询 → 204(空),等了 1005 ms 超时返回

分步演示

长轮询
本步的对象

    本文用到的工具与边界

    • 本机 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,数字每次运行会有小幅抖动。gunicorn gthread 与 gevent worker
    • 没有验证:多进程下事件的共享(需要 redis 发布订阅等,见第 145 篇)、经过 nginx 时 proxy_read_timeout 与缓冲的影响、浏览器端的实现、大量轮询客户端同时超时重连造成的惊群
    京ICP备2026067502号-1京公网安备11010502063487号