56 lines
3.5 KiB
Bash
Executable File
56 lines
3.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# 并行生成:bash ml/gen/run_parallel.sh <每进程条数> <进程数> [起始种子=1] ["--consensus 4"]
|
||
# 例:8 核机器 5 万条 → bash ml/gen/run_parallel.sh 6250 8
|
||
# 2026-10-18 第五轮(审查 N-7 / N-16 / 缺口 1):
|
||
# - 每个种子先写 shard_XXXX.jsonl.part,写完才改名 → 中断/并发都不会留下被截断却看似完整的 shard;
|
||
# - 已存在的 shard_XXXX.jsonl(写完的)直接跳过;没写完的 .part 由 gen_dataset 从断点续写(只补剩下的条数);
|
||
# - 逐个 wait 子进程并检查返回码(此前裸 `wait` 恒为 0,某个 node 崩了也会继续统计);
|
||
# - 每 60 s 往控制台打一行节拍(已写条数 + 各进程最新进度),网页「终端输出」可见。
|
||
set -e
|
||
N=${1:-500}; P=${2:-2}; S0=${3:-1}; EXTRA=${4:-}
|
||
cd "$(dirname "$0")/../.."
|
||
mkdir -p ml/data
|
||
pids=(); seeds=()
|
||
for ((i=0;i<P;i++)); do
|
||
s=$((S0+i)); f=ml/data/shard_$(printf %04d $s).jsonl
|
||
if [ -f "$f" ]; then echo "[gen] 种子 $s 已完成,跳过"; continue; fi
|
||
( node ml/gen/gen_dataset.cjs --n $N --seed $s --out "$f.part" $EXTRA 2>> ml/data/log_$s.txt && mv "$f.part" "$f" ) &
|
||
pids+=($!); seeds+=($s)
|
||
done
|
||
t0=$(date +%s); tl=$t0
|
||
while :; do
|
||
alive=0; for p in "${pids[@]}"; do kill -0 $p 2>/dev/null && alive=$((alive+1)); done
|
||
[ $alive = 0 ] && break
|
||
sleep 5
|
||
if [ $(( $(date +%s) - tl )) -ge 60 ]; then
|
||
tl=$(date +%s)
|
||
n=$(cat ml/data/shard_*.jsonl.part 2>/dev/null | wc -l)
|
||
last=$(for s in "${seeds[@]}"; do tail -n1 ml/data/log_$s.txt 2>/dev/null; done | head -n 2 | tr '\n' ' ')
|
||
echo "[gen 节拍] $(( (tl-t0)/60 )) 分钟 运行中 $alive/${#pids[@]} 进程 本批已写 $n 条 $last"
|
||
fi
|
||
done
|
||
# 判定按产物而不是 wait 的退出码:2026-10-18 实测 28 个种子跑了 5 小时后全部 wait 报失败,
|
||
# 但每个 .part 都是完整的 1786 行(node 打了 done、mv 却没执行)——Git Bash 长跑后 wait 的返回码不可靠。
|
||
# 短产物分两种:网页点「停止」把 node 杀掉(.part 是断点,续跑接着写,不是失败)和 node 自己报错。
|
||
# 只有日志尾部有报错特征才算失败;143 让网页显示「已停止」而不是「失败(返回码 6)」(monitor.html:508 同一口径)。
|
||
crashed=0; stopped=0; sn=0
|
||
for k in "${!pids[@]}"; do
|
||
s=${seeds[$k]}; f=ml/data/shard_$(printf %04d $s).jsonl
|
||
w=0; wait ${pids[$k]} || w=$? # 记下来但不当判据:长跑后 Git Bash 的 wait 返回码不可靠
|
||
if [ -f "$f" ]; then continue; fi
|
||
n=0; [ -f "$f.part" ] && n=$(wc -l < "$f.part")
|
||
if [ "$n" -ge "$N" ]; then mv "$f.part" "$f" && echo "[gen] 种子 $s 产物完整($n 行),补改名" && continue; fi
|
||
if tail -n 4 ml/data/log_$s.txt 2>/dev/null | grep -qE '^(Error|.*Error:|.*SyntaxError|.*heap out of memory|Traceback|.*throw )'; then
|
||
echo "[gen] 种子 $s 失败:.part 只有 $n/$N 行,最后几行:"; tail -n 5 ml/data/log_$s.txt || true
|
||
crashed=1
|
||
else
|
||
echo "[gen] 种子 $s 已停止:写好 $n/$N 条,断点保留在 $f.part,点「继续训练」从第 $((n + 1)) 条接着写(子进程返回码 $w)"
|
||
stopped=1; sn=$((sn + n))
|
||
fi
|
||
done
|
||
[ $crashed = 0 ] || exit 6
|
||
# 全被停止时不跑 stats.cjs:分片还没改名,统计口径没变,重算一遍只会让「补量」看起来原地不动
|
||
[ $stopped = 0 ] || { echo "[gen] 本轮是被停止的,没有报错:$stopped 个种子共保住 $sn 条,续跑不重复生成"; exit 143; }
|
||
node ml/gen/stats.cjs ml/data/shard_*.jsonl > ml/data/stats.json
|
||
cat ml/data/stats.json
|