为长仿真调内存¶
进阶
前置阅读: GPU 加速教程
跑 100+ 秒仿真、case2000+ 大网络、或者 batch 模式 16 worker 同时跑——内存吃紧是常态。本页给一组逐级递增的优化清单。
第一档:YAML 调参(无需改代码)¶
关掉非必要的轨迹保存¶
关掉 batch 元数据里的额外字段¶
output:
keep_failed: false # 不保留拒绝的样本(默认就是 false)
format: hdf5 # 比 npz 小 2-3 倍
metadata: parquet # 比 csv 小 10 倍
第二档:torch 引擎的 chunk_seconds¶
如果你已经切到 torch 后端:
效果(case39 + 10 s 仿真):
chunk_seconds |
峰值显存 | 速度 |
|---|---|---|
null(默认) |
1.0 GB | 100% |
1.0 |
0.5 GB | 95% |
0.5 |
0.25 GB | 90% |
0.1 |
50 MB | 70% |
详细见 GPU 加速 — 内存爆炸怎么办。
第三档:减小 batch 并发¶
每个 joblib worker 复制一份 case 数据 + 求解器状态,并发越多内存越大。
第四档:禁 BLAS 多线程嵌套¶
joblib worker × OpenBLAS 多线程 = O(n²) 资源消耗。用环境变量限制:
export OPENBLAS_NUM_THREADS=1
export MKL_NUM_THREADS=1
export OMP_NUM_THREADS=1
python -m pylectra run examples/batch_case39.yaml
每个仿真单线程跑,但你 worker 多 → 总 CPU 用满,总内存却小很多。
第五档:分段写盘¶
非常长的 batch(10 000+ 样本)一次跑完风险大——拆成 100 样本一档:
from pylectra.run import run
import os
base_seed = 42
chunk_size = 100
total = 10000
for offset in range(0, total, chunk_size):
out_dir = f"./batch_chunks/chunk_{offset:06d}"
if os.path.exists(out_dir):
continue # 跳过已完成
run("examples/batch_case39.yaml",
scenarios={"count": chunk_size, "seed": base_seed + offset},
output={"directory": out_dir})
之后用 pandas 把所有 metadata 拼回去:
import pandas as pd, glob
metas = pd.concat([pd.read_parquet(f) for f in glob.glob("./batch_chunks/*/metadata.parquet")])
metas["sample_id"] = metas.index # 重新编号避免冲突
第六档:删除中间状态¶
如果你的 Python 脚本里不释放 SimulationResult,N 个结果叠在内存里:
results = [] # ✗ 越加越多
for cfg in configs:
out = run(cfg, plot=False)
results.append(out.result.max_angle_deviation_deg) # 只留标量
# 或者
del out # 显式 del
import gc
gc.collect() # 强制回收
第七档:换更小算例¶
case2000+ 的内存瓶颈通常是完整时序——每个 sample H5 几百 MB。如果你只关心标量指标(最大角偏差、CCT),完全可以只存 metadata:
当前版本暂不支持"丢弃 H5 只留 parquet"——临时方案:跑完后 rm samples/*.h5。
第八档:换 case 表示¶
如果你做大量小信号扫描(skip_integration: true),其实只需要 case + 模型参数 + 平衡点——不需要时序。每个样本的 metadata + eigenvalues 几 KB 而已。
mode: batch
skip_integration: true
small_signal: {kind: finite_difference}
output:
format: npz # 比 hdf5 简单
metadata: parquet
内存监控¶
# Linux / macOS
htop # 实时;F10 退出
# Windows
tasklist | findstr python
# 程序里实时打印
import psutil, os
proc = psutil.Process(os.getpid())
print(f"RSS = {proc.memory_info().rss / 1024**3:.2f} GB")
排错¶
"MemoryError" / Killed by OS¶
排查顺序:
- 看
n_jobs是不是过大 → 砍半 - case 多大 →
pylectra info看total memoryvs case 大小 - dense_n 是否过大(torch 后端) → 调到 50
- 是否在脚本里堆积了 results 列表
- 终极:分段跑 + 间隙
del+gc.collect()
swap 暴增¶
OS 用上了硬盘虚拟内存——速度会暴跌。立刻砍 n_jobs,否则 batch 时间从 10 分钟变 10 小时不夸张。
接下来读什么¶
- GPU 加速教程 — chunk_seconds 完整文档
- 并行 batch 优化 — n_jobs / BLAS 线程
- 常见问题 FAQ — 内存相关问题汇总