Files
SystemSimulationApp/docs/other/八路结果处理与网页保存优化-2026-09-11.md
T
lujingze 3bc4be3c06 优化原生结果编码传输与浏览器缓存,记录八路性能基线
原生结果series通过字节索引直传,C端使用Ryu精确回读编码和64 KiB批量写出;网页采用Float64缓存和CSV工作线程,减少结果处理与保存等待。

补充八路AME曲线核查、全流程分阶段计时、独立编码基准和复现工具,固定后续优化采用修正八路及rtol=1e-8。C写出1.1808→0.1638 s,点击到可查看8.0100→6.9756 s。

验证:最终10项编码专项、29项相关后端回归通过;8份原生结果逐位一致,16次网页结果/CSV/刷新恢复通过。前端构建及缓存/CSV专项在本轮结果处理工作中通过。环境、原始大结果与临时构建不纳入Git。
2026-09-11 15:09:15 +00:00

159 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 八路结果处理、浏览器保存与 CSV 优化(2026-09-11)
本轮针对“点击运行→结果可查看”“点击运行→浏览器保存完成”“CSV 下载保存”三个用户关注的时间点实施优化。基线为 `808c484`,主案例仍是 [修正后的八路工程](../../tests/data/test-mql-8-corrected.json),未退回四路。此前各阶段成本见 [八路评估报告](八路模型计算效率与网页阶段计时-2026-09-11.md)。
## 实现
### C 数值 JSON 直接进入 HTTP 结果流
C 继续生成原有 `result.json`,数值仍使用 `%.17g`,新增可选 `--result-index` 小索引文件。索引通过写文件时的实际字节位置标出完整 `series` 对象,包含版本、边界、文件长度和采样数;主结果成功关闭后才发布索引,定位或文件写入失败返回错误。
网页流式请求启用原生片段传输:Python 校验索引版本、整数边界、文件长度与布局,只解析较小的诊断和最终值;采样数组保留为 C 已生成的 JSON 字节。返回时标准 JSON 编码器处理模型元数据、名称、单位和诊断,原始数值片段直接放入 `result.series`,不再次转换为 Python 浮点数组或重新编码这些数组。浏览器仍收到原有 JSON 对象和普通数字数组,没有改成二进制接口。
字节内容在临时工作目录删除前已经独立持有,任务保留及重复 GET 查询也可直接返回。默认 Python 调用、同步 HTTP 仿真与独立 CLI 仍提供普通结果对象;取消、失败和部分结果的状态规则保持原合同。原始片段仅来自受控 C 输出,用户模型文字继续经过标准 JSON 转义,不按字符串搜索猜测边界。
C 的 JSON 数字格式化成本仍存在;本轮着重省去大数组在 Python 中的解析和再次编码。方程、牛顿/二分算法、积分器、误差限、事件点与采样没有修改。
### 浏览器打包保存与旧缓存兼容
原保存方式按每个输出列写独立块,八路一次结果有 1785 个数据写入、14 个顺序事务。新方式把短列连成固定容量的 Float64 数据块:完整八路约 7 块,每块最多 2 MiB,加 1 条头记录,在单次原子事务内提交;只有成功提交且仍是最新保存请求时,才更新小型 sessionStorage 指针。
复制过程分批让出主线程;换结果会停止旧保存,失败不发布新指针,只清理本页拥有的缓存。新记录带 `packed-f64-v1` 标记,读取通过少量 `getAll` 结果恢复;旧 IndexedDB 按列格式及旧 sessionStorage 格式继续可读。记录缺块、重叠、错误长度或未知布局会明确失败,不返回残缺结果。
### CSV 改在工作线程中生成
网页不再把全部曲线 JSON 回传给后台 CSV 接口。主线程按最多 1 MiB 的 Float64 数据批次转移给专用 Worker,Worker 按列序生成 CSV Blob;主线程保持可响应,重复点击、切换结果和组件卸载均有任务清理。保留原下载按钮和文件名规则,旧 HTTP CSV 接口仍可单独使用。
保留 time 首列、变量元数据顺序、原始单位、全部原始采样、UTF-8 BOM、CRLF 与 CSV 转义。数字使用可精确回读的最短十进制并保留负零;例如整数可能省掉 `.0`,所以 CSV 文本及文件 SHA 会变化,数值必须逐单元精确一致。未降低精度、删列或抽样来缩短用时。
## 验证条件
- 输入 SHA256:`670977bef67e62d9c66e8af497bada208bd72a7301be45128d185d47282cf288`;157 元件、178 条连接、132 状态、1784 输出变量。
- 八路 0~10 s、输出间隔 0.01 s,1002 个原始采样(含事件点);CVODE BDF / SUNDIALS 7.4.0,`rtol=1e-8`、`max_step=1e30`,状态绝对误差限保持质量1e-14、内能1e-8、速度/位移1e-12(各自SI单位)。
- 同一 Linux Xeon Silver 4210R 虚拟机、GCC 13.3.0、现有 Python .venv,正式网页使用 Node 24.18.0 构建和 Chromium 151.0.7922.34;未安装新环境或新增生产依赖。
- 旧版后台从 Git `808c484` 导出 app/native/schemas 到隔离目录,前端使用上一轮保存的同提交正式资产;优化版使用本轮源码。两者都是真实服务,不注入结果或模拟网络。
- 依次运行旧版无插桩、优化版无插桩、优化版分阶段诊断三组;每组预热一次、正式三次。正式计时期间没有安排并行求解、大编译或大文件比对;输出比较留到计时结束。
- 每轮先公开导入、导出并核对相同工程,再计点击运行时间;接着进入结果页、选择温度、CSV 和结果文件下载、刷新恢复。浏览器保存完成采用同一个 session 指针提交观察点,允许保存与查看自然重叠。
## 同机重新测得的前后用时
下表均取**无插桩组**预热后三次正式运行的中位数,括号为最小~最大值,单位秒。结果可查看以完成状态 DOM 和运行按钮恢复可用为准,另列两帧后的首次绘制机会以便对应此前报告。保存完成由相同 sessionStorage 指针观察,轮询间隔16 ms并含调度延迟;不是提前显示的保存提示。
| 指标 | 旧版 / s | 优化后 / s | 中位耗时降低 |
|---|---:|---:|---:|
| 点击运行 → 结果可查看(完成 DOM) | 9.8720(9.8700~9.9832) | 8.0341(7.9848~8.0377) | 18.62% |
| 点击运行 → 完成状态首次绘制机会 | 9.8931(9.8904~10.0018) | 8.0547(8.0017~8.0595) | 18.58% |
| 点击运行 → 浏览器保存完成观察 | 11.7740(11.6157~12.6169) | 8.1320(8.0843~8.1468) | 30.93% |
| CSV 点击 → 下载保存 | 5.6103(5.4994~5.7601) | 1.0051(0.9394~1.0077) | 82.08% |
| 刷新 → 结果首次绘制机会 | 0.6095(0.5541~0.6375) | 0.3768(0.3525~0.3980) | 38.18% |
三个目标均有改善:结果可查看节省约 **1.84 s**,结果保存完成节省约 **3.64 s**,CSV 下载保存节省约 **4.61 s**。这些区间重叠,不能相加为一次仿真的节省量。与上轮历史数据略有差异时,以本轮重新运行的旧版对照为计算比例的依据。
| 其他观察 | 旧版中位 / s | 优化后中位 / s |
|---|---:|---:|
| 工程导入到首次绘制机会 | 0.2325 | 0.2445 |
| 进入结果页到首次绘制机会 | 0.1825 | 0.1874 |
| 选择温度到曲线首次绘制机会 | 0.0286 | 0.0288 |
| 结果文件下载保存 | 1.3575 | 1.0118 |
| 刷新到结果DOM | 0.4669 | 0.2496 |
| 结果就绪DOM到保存指针观察 | 1.9040 | 0.0995 |
两组 C 纯求解中位数分别为 **6.1083 / 6.1013 s**,进程全程分别为 **8.0204 / 7.4582 s**。每次仍是 RHS 74265、接受6974、拒绝454;本轮收益来自结果处理与保存,而不是改变求解精度或少算输出。结果文件下载不是本轮主要改动,有限样本的时间变化不单独宣称为该功能优化收益。
下载完成计时包含 Playwright 通知和 saveAs 的文件系统成本;首个 DOM 后的两帧只是绘制机会,未直接测 GPU。正式页面均经本机回环 HTTP 访问,没有模拟远端网络。分阶段组相比优化版无插桩组有几%波动,其纯求解也从约6.10 s变到约5.94 s;CSV下载完成还有自动化/磁盘调度波动,故加速比例严格来自上面的两组无插桩对照。
![八路三个目标用时的前后对照](assets/2026-09-11/postprocess-20260911-before-after.png)
可缩放版本:[SVG](assets/2026-09-11/postprocess-20260911-before-after.svg)。图的“result visible”为完成状态DOM,与主表第一行相同。
## 优化后的后台阶段
分阶段服务使用隔离的 C 主程序时钟和真实函数包装;数值内核逐字节相同。按每个 X-Simulation-Id 关联网页与后台,以下为正式三次的秒数(中位、范围)。
| 阶段 | 中位数(最小~最大)/ s |
|---|---:|
| XML 校验 | 0.0227(0.0219~0.0232) |
| 网络编译 | 0.0393(0.0372~0.0425) |
| C 代码生成 | 0.0557(0.0539~0.0934) |
| 构建缓存核验(均命中) | 0.0339(0.0327~0.0340) |
| C 纯积分 | 5.9407(5.9370~6.0256) |
| C 输出投影 | 0.0799(0.0774~0.0813) |
| C 原始 JSON 与索引写出 | 1.1643(1.1578~1.1762) |
| Python 原始结果文件读字节 | 0.0250(0.0107~0.0269) |
| Python 解析小索引与元数据 | 0.0012(0.0011~0.0015) |
| 索引读取与片段整理全程(含上两项) | 0.0472(0.0350~0.0486) |
| 响应接口元数据组装 | 0.0172(0.0168~0.0176) |
| 响应小元数据 JSON 序列化 | 0.0329(0.0328~0.0329) |
| 序列化后至 ASGI 最后响应完成 | 0.0747(0.0528~0.1222) |
| 后台 HTTP 全程(父区间) | 7.5315(7.5174~7.6975) |
旧版阶段诊断中,Python 完整结果 JSON 解析约0.551 s、HTTP结果序列化约1.193 s;新路径只解析小元数据约0.0012 s,序列化约0.0329 s。旧阶段分项来自上一轮诊断报告,不用于替代本轮端到端的同机重新比较。C格式化/写出仍约1.16 s,后续还有优化空间。
原生片段整理全程约0.0472 s,包含读文件、小JSON解析、校验和series字节持有;不能与其子项重复相加。C main全程约7.1957 s,Python原生执行包装约7.2336 s,worker全程约7.4409 s,也都是包含子阶段的父区间。诊断产物保留另约0.00055 s;服务器send、后台生产和浏览器等待可能重叠。
## 浏览器保存与 CSV 的实际细分
以下来自优化后的分阶段组,所有时间为观察区间,含相应异步等待与调度。
| 观察区间 | 中位数 / s |
|---|---:|
| 点击运行至调用fetch | 0.0187 |
| 最终结果 JSON.parse | 0.0982 |
| UTF-8 解码总计 | 0.0297 |
| 结果解析结束至保存提交指针发布 | 0.1186 |
| IndexedDB 单次事务窗口 | 0.0549 |
| 完成状态DOM至保存完成观察 | 0.0829 |
| CSV工作线程start发送至finish发送 | 0.0681 |
| CSV finish发送至完成消息接收 | 0.3889 |
| CSV点击至Blob下载锚点 | 0.4893 |
| 结果文件点击至Blob下载锚点 | 0.5905 |
实际八路三次保存均为 **1 个事务、约55 ms**;事务前还需要打包和调度,所以不能把55 ms当成从计算结束到保存完成的全部时间。浏览器仍在同一提交完成后发布恢复指针,没有通过放宽持久化完成标准来提速。
CSV三次均未发HTTP请求。按批传输约68 ms;finish发出到完成消息收到约389 ms,含剩余工作线程计算、启动/排队和消息传递,不冒称纯Worker CPU时间。点击至Blob准备好约489 ms,实际下载保存的主结论仍使用无插桩组约1.005 s。
新CSV为31,820,845字节,旧版32,346,795字节,减少约1.63%;主要收益是省去全量JSON往返和后台逐单元格式化,并将生成放在工作线程,不能仅归因于文件体积变小。CSV编码采用Float64精确回读方式,数值一致性单独验证。
## 正确性与回归
29 项后端相关回归通过,覆盖原生执行、默认同步接口、真实 ASGI 流式响应与重复任务 GET、用户/异常断线取消后的部分结果、心跳、索引损坏与截断文件、JSON 边界转义、独立 C 程序和旧 CSV HTTP 合同。后续补全严格索引版本及 I/O 异常处理后,6 项传输专项再次通过。
6 项真实 IndexedDB 专项通过,覆盖完整八路形状的值、负零、空列、旧缓存、缺块/重叠、头记录写入失败、保存竞态和跨页面隔离。6 项 CSV 专项通过,包括 1052929 个值的精确回读、最小子正规数、极大数、负零、列顺序和转义、无 CSV HTTP 请求、重复点击与错误重试。专项合成数据耗时只用于功能诊断,不充当正式八路测量。正式 TypeScript/Vite 构建通过。
本轮发现已有 `tests/test_native_codegen.py` 引用的 `tests/fixtures/native-skill-test.xml` 在当前提交缺失,从 `5d5a2e1:tests/data/native-skill-test.xml` 原样恢复到其现行测试路径,保证相关回归可运行。没有放回浏览器输入目录或改变这份测试资料的物理内容。
三组共 **12 次**真实八路运行全部完成10 s,无页面错误。每次公开导出工程都与固定输入的全部参数、连接与设置一致;全部 `series`、`final` 与优化前原生基准精确相等。12份CSV合计 **21,462,840 个数值单元**与基准精确相等,各组内部CSV字节稳定;旧新文本差异符合前述编码规则。12次刷新前后的完整结果一致。
另外,4份分阶段组C原始结果文件的 `series/final/finalState` 均与旧原生基准逐值相同,证明后处理改动没有改变积分轨迹或事件点。这里只比较数值,不要求运行耗时等诊断字段在不同运行间相同。证据:[全量网页/CSV核对](../../test/postprocess-20260911/equality.json)、[C原始状态核对](../../test/postprocess-20260911/native-parity.json)。
## Amesim 范围
本轮处理优化不改变计算结果,沿用 [当前八路 AME 归档核查](test-mql-8当前AME归档与完整曲线核查-2026-09-11.md) 的差异记录。完整数值逐值不变后,原有早期压力/温度差及约0.9834 s碰撞力尖峰也会保留;不能把后处理提速解释为八路物理曲线验收通过。
当前没有可信 Amesim CPU/墙钟记录,也没有可调用的 Amesim 安装,速度对比仍跳过。后续继续使用修正八路,在相同输入、精度与完整采样下核查正确性与用时。
## 文件与复现
代码入口为 [原生片段传输](../../app/simulation/native_codegen/transport.py)、[C 结果索引](../../native/runtime/main.c)、[浏览器保存](../../frontend/src/resultPersistence.ts)、[CSV 导出任务](../../frontend/src/resultCsvExport.ts) 和 [CSV Worker](../../frontend/src/resultCsv.worker.ts)。
输入快照、隔离旧版、构建、运行结果和截图位于 `test/postprocess-20260911/`;环境仍在 `.venv/native/`。这些大型运行产物和环境均在 Git 忽略范围,本轮未提交或推送 Git。
- [三组逐次与汇总JSON](../../test/postprocess-20260911/summary.json)、[各阶段CSV](../../test/postprocess-20260911/timings.csv)
- [旧版网页记录](../../test/postprocess-20260911/browser-baseline/summary.json)、[优化版网页记录](../../test/postprocess-20260911/browser-optimized/summary.json)、[优化版分阶段记录](../../test/postprocess-20260911/browser-profiled/summary.json);每次截图、输入、结果与刷新文件保存在对应组子目录,后台逐请求阶段位于 `backend-profiled/requests/<simulationId>/stages.json`。
- [源码与输入清单](../../test/postprocess-20260911/source-manifest.json)
- [后端回归](../../test/postprocess-20260911/backend-tests.log)、[传输专项复测](../../test/postprocess-20260911/backend-transport-final.log)、[正式前端构建](../../test/postprocess-20260911/frontend-build.log)
- 计时脚本 [backend_stage_profile.py](../../tests/manual/backend_stage_profile.py)、[browser_stage_profile.mjs](../../tests/manual/browser_stage_profile.mjs);数值复核 [compare_browser_stage_outputs.py](../../tests/manual/compare_browser_stage_outputs.py)。
```bash
# 后端相关回归
.venv/bin/python -m unittest tests.test_native_result_transport tests.test_native_codegen \
tests.test_generic_system_xml_simulation tests.test_result_csv_export tests.test_native_only_backend -v
# 当前正式网页的独立服务与计时:两个终端分别运行,输出目录必须为新目录
.venv/bin/python tests/manual/backend_stage_profile.py --plain \
--output-dir test/new-results-service --port 8021
LD_LIBRARY_PATH="$PWD/.venv/native/browser-libs/usr/lib/x86_64-linux-gnu${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" \
.tools/node-v24.18.0-linux-x64/bin/node tests/manual/browser_stage_profile.mjs \
--url http://127.0.0.1:8021 --mode control --runs 3 --output test/new-results-browser
```