返回几十万行数据,是一次性 jsonify 还是流式?流式能省多少内存、慢多少?流到一半出错客户端怎么知道?客户端断开会怎样?这篇用真实的 gunicorn 与 PostgreSQL 服务端游标,把答案逐项量出来。
(每种方式各用一个全新的 worker 进程,避免上一次请求留下的内存影响峰值) 一次性 jsonify 状态 200 响应头到达 1698 ms | 首块数据 1698 ms | 全部读完 1718 ms | 41.6 MB | Content-Length: 41592617 | Transfer-Encoding: None | worker 空闲 72 MB,峰值 RSS 424 MB(多 352 MB) 流式 NDJSON 状态 200 响应头到达 104 ms | 首块数据 114 ms | 全部读完 5314 ms | 41.6 MB | Content-Length: None | Transfer-Encoding: chunked | worker 空闲 72 MB,峰值 RSS 73 MB(多 1 MB) 流式 JSON 数组 状态 200 响应头到达 1 ms | 首块数据 100 ms | 全部读完 5258 ms | 41.6 MB | Content-Length: None | Transfer-Encoding: chunked | worker 空闲 72 MB,峰值 RSS 73 MB(多 1 MB)
上一篇:大批量 JSON 响应;下一篇:SECRET_KEY 的用途。
每种方式单独起一个 worker:第一次我在同一个 worker 里连续测,上一次请求留下的内存把后面的峰值抬高了,结果不可信;而且我第一次忘了给生成器加 stream_with_context,流式路径返回了一个 141 字节的错误页,我是看到这个异常小的响应才发现的。
json.loads 解析成功,500000 个元素,第一个 {'id': 1, 'name': 'user1', 'email': 'user1@example.com', 'score': 1.5},最后一个 {'id': 500000, 'name': 'user500000', 'email': 'user500000@example.com', 'score': 750000.0}状态码: 200 | Transfer-Encoding: chunked 客户端读取结果: 读取时抛出 IncompleteRead
服务端日志: ['generator closed (client went away)', 'generator finally']