ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

tick-stock-panel 回测子进程隔离架构深度解析:spawn worker、持久 run ID 与刷新重连完整指南

tick-stock-panel 回测子进程隔离架构深度解析:spawn worker、持久 run ID 与刷新重连完整指南 tick-stock-panel 回测子进程隔离架构深度解析spawn worker、持久 run ID 与刷新重连完整指南【免费下载链接】tick-stock-panelTSP自托管、零运维的 A 股「选股 监控 回测」量化工作台 | LLM能力驱使策略定制个股分析复盘 | 自由接入第三方数据源与个性化扩展数据 | 个人开源项目地址: https://gitcode.com/GitHub_Trending/ti/tick-stock-paneltick-stock-panel 是一款自托管、零运维的 A 股「选股 监控 回测」量化工作台。它的回测系统有一个常被忽视却至关重要的设计重活全部扔给独立子进程干——主 Web 服务只当调度员回测、参数优化、滚动验证、因子挖掘在 spawn 出的全新 Python 进程里跑长任务再落盘成带持久 run ID 的任务档案配合 SSE 断线重连你刷新页面、切换标签页进度都不会丢。本文带你完整看懂这套「子进程隔离 持久 run ID 刷新重连」的架构。为什么不在主进程里直接跑回测一次策略回测可能要吃掉几个 GB 内存、跑几分钟。如果它和 API 服务挤在同一个进程里会发生三件事内存爆炸连累全家回测 OOM 时整个 Web 服务一起挂掉连自选股列表都打不开状态污染NumPy/Polars 等扩展模块被回测加载后主进程的内存再也回不干净卡死无解重计算占住 GILHTTP 请求全部排队。tick-stock-panel 的解法很直接worker.py 里的run_worker_task统一使用mp.get_context(spawn)创建全新解释器进程而非 fork 复制回测结束后进程直接销毁内存干干净净还给操作系统。spawn worker一次任务、一个全新进程任务如何打包进子进程主进程通过 make_worker_task 把配置序列化成纯 JSON 字典包含四种任务类型backtest策略回测、optimize参数优化、walkforward滚动验证、mining因子挖掘。日期等不可直接序列化的对象都会先转成 ISO 字符串子进程启动后在 _decode 系列函数 里还原。子进程入口 _worker_entry 做了几件值得学习的事不继承任何状态数据仓库、策略引擎、因子注册表都在子进程里从头加载自定义因子通过load_into_registry从磁盘恢复与主进程行为完全一致全程采样内存峰值_PeakRssSampler 每 50ms 记录一次 RSS任务报告里会附带peak_rss_bytes、serialized_result_bytes等指标帮你量化这个回测到底吃了多少内存快速收尸结果入队后先close join_thread冲刷管道再os._exit(0)跳过解释器收尾避免慢退出撞上父进程的 10 秒等待预算。父子进程之间只有三种消息子进程与父进程只通过一条队列通信消息类型固定为progress进度、result结果、error错误 完整 traceback。父进程在 run_worker_task 的主循环 中以 0.1 秒为步长轮询把进度透传给上层把结果原样返回。两个容易翻车的边界它都做了兜底取消上层触发取消事件后子进程会优雅退出若 5 秒宽限期_CANCEL_GRACE_SECONDS内仍未停止父进程直接terminate()并抛出明确报错子进程活得太慢结果已送达但进程 10 秒内没退出时父进程强制结束它但依然采纳已送达的成功结果结果中标记worker_exit_forcibly: true绝不把跑成功的回测当失败丢弃。对应行为可参考 test_worker_process.py 中的两个用例。持久 run ID挖掘任务刷新页面后还在跑短任务靠内存就够了但因子挖掘动辄几十分钟必须能活过刷新甚至服务重启。tick-stock-panel 为此把任务档案落盘到磁盘核心是 mining_jobs.py 里的MiningRunStorerun_id 就是目录名每次任务用校验过的 UUID hex 作为 run ID独占一个目录里面有manifest.json状态机queued → running → succeeded / failed / cancelled、summary.json最新进度摘要、events.jsonl单调递增编号的紧凑事件流和若干 Parquet 产物事件带自增 IDappend_event 给每条事件分配递增id只保留最近一批MAX_EVENTS天然支持从第 N 条继续读的游标语义签名去重相同请求 相同数据指纹的任务由find_by_signature直接复用不会重复烧算力重启自愈服务启动时 recover_interrupted 扫描所有仍处于活跃状态的 run统一标记为 interrupted避免僵尸任务。后台编排则由 mining_manager.py 的MiningJobManager负责每个 run 一个守护线程 一个取消事件worker 的每帧进度都会实时写进events.jsonl。刷新重连SSE 双通道让进度永不丢失回测流job key 去重 进度回放策略回测走 /api/backtest/strategy/stream 这个 SSE 接口重连能力来自 模块级任务表相同参数的请求会算出同一个 job key全部回测参数做 MD5 截取 12 位第二次连接直接订阅已有任务回测只会启动一次每帧进度都追加进job.progress历史列表新连接用游标从头回放刷新后进度条直接从当前位置接上断开连接不会取消任务除非显式调用 cancel结果完成后再保留 5 分钟供重连取回。挖掘事件流Last-Event-ID 游标重连挖掘任务的事件流是 /api/backtest/mining/runs/{run_id}/events重连机制更优雅浏览器 EventSource 断开重连时会自动带上Last-Event-ID请求头服务端据此调用read_events(run_id, after_idcursor)只补发游标之后的事件若发现中间有缺口还会先补推一份summary.json里的最新进度保证画面永远连续。配合 15 秒心跳长任务期间连接不会被代理或浏览器掐断。一句话总结两条链路能力回测流挖掘事件流任务身份参数哈希 job key持久 run ID进度存储内存列表TTL 5 分钟磁盘 events.jsonl重连续传方式进度历史全量回放Last-Event-ID 游标补发断线是否取消任务否否想深入源码从这三个文件开始子进程调度核心backend/app/backtest/worker.py回测 SSE 流与重连backend/app/api/backtest.py持久任务存储与事件游标backend/app/services/mining_jobs.py配套的挖掘设计文档见 docs/mining.md端到端行为测试见 backend/tests/backtest/test_worker_process.py。这套「spawn 隔离 磁盘 run 档案 SSE 游标重连」的组合本质上把内存里的进程和磁盘上的任务解耦了进程可以随时死任务状态永远可恢复——这正是自托管量化工作台在低配服务器上也能稳定长跑的关键。【免费下载链接】tick-stock-panelTSP自托管、零运维的 A 股「选股 监控 回测」量化工作台 | LLM能力驱使策略定制个股分析复盘 | 自由接入第三方数据源与个性化扩展数据 | 个人开源项目地址: https://gitcode.com/GitHub_Trending/ti/tick-stock-panel创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表