通用程序资源限制器 — 进程树级 CPU / 内存 / 磁盘 IO / 进程数硬限制
limit [选项] -- <命令> [参数...] 把命令及其所有子进程整体关进一个资源容器,
像 Docker 一样限制 CPU / 内存 / 磁盘 IO / 进程数。Go 实现,零依赖单文件二进制。
| 平台 | 状态 | 后端 |
|---|---|---|
| Windows | ✅ 全部选项可用,全部实测 | Job Object(Windows 原生进程组容器,Windows 容器本身就用它实现) |
| Linux / macOS | cgroup v2 / rlimit(尚未移植) |
非 Windows 平台的二进制可以正常解析选项、看 --help;真正执行到「施加限制」时
明确报错退出,不会静默放行——不会让你误以为限制生效了。移植前,
linux 下临时等价手段是 systemd-run --scope -p CPUQuota=25% -- <命令>。
:: 限速解压大压缩包,全程不卡机
limit --cpu 25% --mem 2G --io 50 -- 7z x big.7z -oD:\out
:: HDD 保护磁头: --iops 限「寻道频率」(设备层事务/s),src / dst 任一盘超了就压
:: 大文件顺序拷贝几乎不受影响,大量小文件被削得最狠
limit --iops 200 D: E: -- robocopy S:\ D:\backup /E /J
:: 超时收工(墙钟计时;到期整棵树被终止,退出码 124 同 coreutils timeout)
limit --timeout 2h -- robocopy S:\ D:\backup /E /J
:: 缓存写程序(7z 等)限不住回写?用 CPU 顶当 IO 节流阀——对所有 IO 都生效
limit --cpu 5% -- 7z x big.7z -oHDD:\out
:: 后台转码给前台让路
limit --prio idle --cpu 10% -- ffmpeg -i in.mp4 out.mkv
:: 防失控程序吃爆内存
limit --mem 1G --mem-total 4G -- some_tool| 选项 | 说明 |
|---|---|
--cpu <百分比> |
CPU 硬顶(调度器级强制执行) |
--mem <大小> |
单进程 commit 内存硬顶(512M/4G) |
--mem-total <大小> |
整棵树 commit 内存硬顶 |
--io <MB/s> |
磁盘 IO 速率上限(整 Job 聚合,读写合计)。实测有效(--io 20 → 16.9MB/s);是天花板,负载自然速度低于它时不生效 |
--iops <次数/s> [盘...] |
限寻道频率=物理盘设备层事务数/秒(免管理员)。不给盘符=所有固定卷,也可 --iops 200 D: E: 只盯这两盘,任一盘超目标就压(同一物理盘只算一次)。大文件几乎无感,大量小文件压得最狠——见要点 5 |
--procs <个数> |
进程数上限(含子进程树) |
--affinity <掩码> |
CPU 亲和性(0x0F 或 0,2-5) |
--prio <级别> |
idle|below|normal|above|high |
--io-prio <级别> |
verylow|low|normal|high —— IO 优先级,让路给其他程序。不挂起进程,零卡死风险,是"别拖卡机器"的首选 |
--timeout <时长> |
墙钟超时,到期 TerminateJobObject 整棵树并返回 124(90s/10m/1h,纯数字=秒) |
--no-kill-on-close |
limit 被杀时不拉子进程陪葬(默认陪葬) |
退出时打印:退出码、CPU 时间(user+kernel)、峰值 commit(单进程/整棵树)。
go install github.com/Weidows/limit@latest
go build -o limit .| 限制 | 测试 | 结果 |
|---|---|---|
--cpu |
burn 4 线程,5%/10%/25% 三档 | 5%≈1 核、10%≈2 核精确;上限高于线程需求时不触顶 ✅ |
--mem |
alloc 分配 1024MB | 254MB 处分配失败,错误码 1455 ERROR_COMMITMENT_LIMIT ✅ |
--io |
diotest 直写拷贝 | 读写合计精确压在档位上 ✅ |
--iops(设备层) |
4000×64KB 小文件,D:→E:,robocopy /J |
--iops 200 14s→44.6s、实测 200/s;--iops 100 14s→78.5s、实测 112/s ✅ |
--iops(大文件) |
124 文件/51GB(平均 432MB),D:→F: 单文件 5.21GB 对拷 | 自然事务率仅 84/s;--iops 100 75.7s→82.4s(仅慢 8.8%)——大文件本来就不该被 --iops 罚 ✅ |
--io 精度 |
同语料(自然 62MB/s),--io 20 |
实测 16.9MB/s,精确生效 ✅ |
--iops 自动停用 |
大块顺序 IO 负载(平均 1.4MB/次) | 自动关掉挂起限速并提示,62→56MB/s(仅慢 10%),不再卡死 ✅ |
⚠ --iops 风险 |
旧控制律(5ms 切换)跑大文件 | 曾把 robocopy 卡成 WrResource 僵尸(taskkill 杀不掉,需重启)并锁住目标目录 ❌ |
--timeout 3s |
cmd /c ping -n 30 |
3s 后整棵树被终止,无残留进程,退出码 124 ✅ |
--affinity 0x1 |
burn 2 线程 | CPU 5.55s(绑 1 核)✅ |
--procs 1 |
cmd 里再起 cmd | 孙进程创建被拒 ✅ |
| × 7z | 2GB 包解压 7.5GB 到 HDD | --cpu 当节流阀:小包线性减速;大包把 61MB/s 回写爆发削到 13MB/s ✅ |
| × robocopy | 17000 文件/660MB 拷贝 | 缓冲写数据侧穿透 --io(814 MB/s 无感);加 /J 走无缓冲后 --io 精确生效 ✅ |
实际压制IO后的效果图:
按程序归档的完整数据(负载、档位、耗时、曲线结论)在 docs/MEASURED.md;每实测一个新程序就往那里追加一节。
--cpu相对整机算力:100% = 全部逻辑 CPU(20 线程机上 5% = 1 核)。 上限高于线程需求时不触顶。--mem是 commit 口径硬顶:撞顶时分配直接失败(错误码 1455),类似 cgroup 的memory.max;RSS(工作集)只有软限,这是 Windows 语义。--io是整 Job 读写合计、聚合配额(多盘并行共享一个额度,与微软文档「按盘独立」不符,以实测为准)。 只对无缓冲/直写/写穿透 IO 精确生效——缓冲写程序(xcopy/robocopy 默认模式、7z 等)的数据写完全穿透:WriteFile只进系统缓存即返回,真正落盘的 IO 由内核回写器在 Job 之外全速发出(实测--io 30下 robocopy 814 MB/s、xcopy 506 MB/s,与不限速无异)。解法:robocopy 加/J走无缓冲,--io立即精确生效 (实测/J --io 50→ 37 MB/s);xcopy 无此模式,换 robocopy/J或用--cpu节流阀。 2026-10-27 复测确认它有效(--io 20→ 16.9MB/s);注意它是上限——负载自然速度 (两盘对拷单流约 60MB/s)低于上限时不产生效果,别误判为"没生效"。- 缓存写限不住?
--cpu当节流阀:CPU 顶对所有 IO 类型生效。吃 CPU 的负载 (压缩/解压/转码)被压住后产出速率同步下降;实测 IO 速率 ≈ min(磁盘自然速率, CPU 顶折算速率)。 --iops限的是「设备层事务数/秒」= HDD 寻道频率(这是 HDD 的唯一正解):顺序 1MB 只算 1 次事务(≈100MB/s 也只有 100 事务/s,几乎无寻道),随机 4KB 每 4KB 就 1 次寻道 (同样字节量事务数高 256 倍)。所以同一档位下大文件几乎无感、大量小文件被削得最狠, 吞吐天花板 ≈ 目标 × 平均 IO 大小(200/s ⇒ 4KB 随机 0.8MB/s、1MB 顺序 200MB/s)。 不给盘符就盯所有固定卷,也可--iops 200 D: E:只盯这两盘;任一盘超目标就冻结整棵树 (同物理盘多盘符只算一次)。控制精度:小文件负载目标 200 → 200、目标 100 → 112(略超,因为冻结 期间的在途 IO 不计入欠账);大文件负载基本不受影响(自然事务率本来就低,见下)。 实测:4000 小文件 200 档 ×3.6、100 档 ×6.9;2GB 大文件 200 档零影响、100 档 ×1.7(见 MEASURED.md)。 目标值这么选:先--iops 1000000 D:跑一遍,日志里的「均值」就是该负载的自然事务率, 取 1/2~1/3 即可。注意计数器是整盘口径(同盘其他程序也计入),这正对应"保交互"语义; 背景负载本身高于目标时会被饿住(占空比拉满 + 提示一次)。 大块顺序 IO 会自动停用:每秒探测平均传输块,≥256KB(大文件)就判定"不需要限寻道"并关掉 挂起限速(实测大文件负载仅慢 10%)——这是为了避免挂起撞上同步大块写把进程卡在内核等待 (旧版实测卡死过)。要限带宽用--io,要让路用--io-prio verylow。- 整棵进程树生效:挂起创建 → 入 Job → 恢复,开头几毫秒也不漏。 limit 自身不能再进别的 Job/容器(嵌套限制),会明确报错。
skills/using-limit-cli/SKILL.md— agent 可直接引用的使用技能(选项语义 + 常用配方)

