影子信号走增量:清空十币 560ms → 247ms
compute() 每根新建 TF_DF 换成按 (symbol, timeframe) 缓存的流式对象。worker 进程被复用,所以缓存跨根存活;2 worker 轮流拿 10 币,每个 worker 最终缓存 全部 20 条流,实测内存开销落在噪声里(597→598MiB)。 ## 前提先验,否则整个改动建立在沙子上 init_stream/append_bar **没有 trim**,dataframe 靠 pd.concat 无界增长。所以 增量必然让窗口每根 +1,只能周期性重建拉回,两次重建之间窗口是 [W, W+500] 而非恒定 W。于是必须先证明 compute() 输出对窗口长度不敏感——否则增量等于 静默换掉一批信号,不报错不崩。 verify_window_sens.py:三币 75 个信号窗口,+200/+500/+1000 三档全部逐字段 一致。step39 说的是「命中率在 2000 根饱和」,饱和不等于不变,这是两回事。 ## 对拍 verify_incr_parity.py:三币 1,800 根、21 个命中、各跨 1 次重建边界,逐字段 零分歧。不能引用 HANDOFF §5.5——那验的是 bsp_list 那条链的整体哈希,而这里 是 find_fast_bsp3 那条链,且流式对象跨根复用,状态污染只会让信号悄悄换一批。 对拍顺带定论一件读代码定不了的事:cal_bi_list **不依赖** klc.trend。 init_stream/append_bar 从不调 cal_trend(它只在 get_klc_list 里),所以追加 出来的 klc 其 trend 恒为 UNKNOWN,而批量构建的有值;两者结果逐字段相同。 HANDOFF §5.5 那句「bi.py:221 读 klc.trend,笔的计算依赖它」不成立——221 行 在 cal_trend 自己的循环里,读的是它自身的序列状态。 ## 重建不走 init_stream init_stream 是逐行 dataframe.iloc[idx],正是引擎提速刚修掉的反模式:2001 根 要 238.5ms,而批量 lean 只 74.3ms,慢 3.2 倍。第一版用它重建,10 个币启动时 各来一次,清空反而涨到 1686ms。改用 TF_DF(df, lean=True) 重建,append_bar 靠 _ensure_stream_state 就能接上。 ## 实测 append_bar 21.8ms vs 批量 lean 重建 77.7ms = 3.56x,与研究侧测的 3.7x 一致。 拆解:add_indicators 全表 7.5ms(34%,为加一根重算 2001 行)+ cal_bi_list 整表重扫 11.1ms(51%)+ concat 1.4ms。这两项都在引擎侧,值得反馈。 十币 / 2 核:清空 560→247ms,排队 92→10ms,纯计算 219→108ms。判定从 「加 worker 无用,唯一出路是增量」变成「宽裕,无需优化」。 注意 inner 108ms 里 chan 构建只占约 22ms,其余是 build_htf_zones / find_fast_bsp3 / attach_htf_context。**瓶颈已不在 chan 构建**,再压增量收益 有限。 stream_bars 落到 latency CSV:恒等于 2001 说明缺口判定在每根都回退重建、 增量静默失效,这一点从耗时上看不出是哪一环。实测窗口稳定长大。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -363,7 +363,8 @@ class Shadow:
|
||||
# compute_ms 含排队;queue_ms/inner_ms 把它拆开,用来判断加核有没有用
|
||||
"compute_ms", "queue_ms", "inner_ms",
|
||||
"n_bars", "n_hits",
|
||||
"n_pass", "atr_bp", "lag_med_ms", "lag_ok"])
|
||||
"n_pass", "atr_bp", "lag_med_ms", "lag_ok",
|
||||
"stream_bars"])
|
||||
# 无条件漂移:每根都记,用来和信号根上的条件漂移对照
|
||||
self.f_drf, self.w_drf = _writer(d / "shadow_drift.csv", [
|
||||
"site", "sym", "kline_ts", "delay_label", "delay_ms",
|
||||
@@ -571,7 +572,7 @@ class Shadow:
|
||||
|
||||
t0 = time.perf_counter()
|
||||
payload = (df_l[NUM_COLS].values.tolist(),
|
||||
df_h[NUM_COLS].values.tolist(), baseline, time.time())
|
||||
df_h[NUM_COLS].values.tolist(), baseline, time.time(), sym)
|
||||
loop = asyncio.get_running_loop()
|
||||
from shadow_signal import compute_packed
|
||||
try:
|
||||
@@ -610,7 +611,10 @@ class Shadow:
|
||||
"queue_ms": res.get("queue_ms"), "inner_ms": res.get("inner_ms"),
|
||||
"n_bars": res.get("n_bars", 0),
|
||||
"n_hits": len(hits), "n_pass": n_pass, "atr_bp": atr_bp,
|
||||
"lag_med_ms": lag_med, "lag_ok": int(lag_ok)})
|
||||
"lag_med_ms": lag_med, "lag_ok": int(lag_ok),
|
||||
# 增量流当前窗口。恒等于 2001 说明缺口判定在每根都
|
||||
# 回退重建,增量静默失效——只从耗时上看不出是哪一环
|
||||
"stream_bars": res.get("stream_bars")})
|
||||
self.f_lat.flush()
|
||||
|
||||
if baseline is not None and np.isfinite(baseline):
|
||||
|
||||
Reference in New Issue
Block a user