4.9 KiB
4.9 KiB
优化选股执行性能
Goal
在不改变知行 B1 公式语义和结果持久化契约的前提下,降低全量选股执行的 数据库连接、查询和事务开销,并默认使用 4 个受限 worker 并发评估股票。
用户价值:执行同一目标交易日的选股策略时,系统更快完成且仍能保留完整的 逐股状态、失败原因和七类独立子信号。
Background and Confirmed Facts
RunZhixingB1.execute当前按prepared.source.stocks串行逐股执行: application/run.py:76-122。PostgresMarketDataReader.load_history每只股票建立一次直接 PostgreSQL 连接并读取目标日前的全部 qfq 行情: infrastructure/postgres_reader.py:25-163。PostgresSelectionRunRepository.record_item每只股票建立独立事务,并逐条 插入其信号: infrastructure/postgres_runs.py:139-197。- 市场数据模块已经有可复用的有上限
psycopg_pool.ConnectionPool模式: market_data/infrastructure/postgres.py:34-53。 - 知行 B1 需要保留七类独立子信号;历史 golden 和现有测试是结果兼容基线。
- 本任务不引入 Redis,不改选股公式规则,不实现独立任务队列或新的进度 API。
Requirements
R1. 可观测的性能基线
- 为一次运行记录可复现的阶段指标:有效股票数、历史行数、读取耗时、公式 评估耗时、持久化耗时、worker 数和批次数。
- 指标不能输出数据库 URL、密码、Tushare token 或单股完整行情。
- 运行结果、信号分类和失败状态仍以 PostgreSQL 持久化结果为准。
R2. 连接池化
- 选股读取适配器和结果存储适配器使用应用生命周期内的有上限 PostgreSQL 连接池,不再为每只股票创建和销毁连接。
- 连接池大小必须覆盖 4 个 worker、批量写入和必要的查询余量,不能无限增长。
- 应用关闭时可靠关闭连接池;单元测试可以注入 fake pool/connection。
R3. 批量历史读取
- 保持 qfq、目标交易日截断、升序日期和六年数据保留语义不变。
- 将逐股历史读取改为按股票批量/分块读取;分块大小可配置但必须有默认上限, 防止一次性把全市场历史全部载入内存。
- 当前 B1 公式不使用历史
turnover_rate和total_mv;本任务可以移除历史 查询中不必要的 daily-basic 字段/连接,但目标日数据完整性校验必须保留。
R4. 批量结果写入
- 将逐股
record_item改为按批次写入selection_run_item和selection_signal,默认批次大小为 200,且保留逐股评估异常隔离。 - 批次提交失败时不能标记为成功;运行最终状态必须正确收敛为
success、partial_success或failed。 - 结果查询、重跑唯一性和七类独立信号身份不变。
R5. 四 worker 有界并发
- 默认使用 4 个 worker;并发度必须可配置且至少为 1。
- worker 不得无限创建连接、线程或进程;数据库连接数受池上限约束。
- 同一股票只评估一次;结果顺序不作为业务契约,API 查询仍按既有稳定规则排序。
- 公式计算失败仍只影响该股票,不能丢失其他股票结果。
Out of Scope
- Redis、Celery/RQ/Arq 等外部任务队列或独立 worker 服务。
- 前端轮询协议和执行进度接口重构。
- 公式阈值、指标定义、历史窗口、股票池范围和信号分类调整。
- 结果表结构的大规模迁移或删除历史结果。
Acceptance Criteria
- 在固定历史 fixture 上,现有 golden、七类独立信号和选股状态全部保持一致。
- 单元测试覆盖连接池生命周期、批量历史按股票分组、批量写入、4 worker 并发上限、单股异常隔离和批次失败状态收敛。
- 一次选股运行不再产生每股一次的数据库连接;读取和写入均通过连接池。
- 一次选股运行不再为每只股票单独提交结果事务;结果按批次提交。
- 运行日志/基准输出包含 R1 指标,并能区分 read/evaluate/persist 三段耗时。
- 使用实际 PostgreSQL 数据或等价可复现 harness 验证 4 worker 下运行成功, 且没有出现超出连接池上限的连接创建。
- 选股 HTTP 契约、重跑保护、最终分页结果和失败列表相关测试通过。
- 不引入 Redis,工作区只包含本任务相关改动。
Open Questions
无阻塞问题。批量大小默认 200,worker 默认 4;两者保持配置化,后续以基准结果调整。