
简介Windows刷CPU使用率工具通过浏览器即可模拟指定CPU负载面向系统管理员、开发者和硬件爱好者用于压力测试、性能评估与系统稳定性验证。资源包内含2个文件分别为页面文件与jQuery脚本整体仅34KB无需安装复杂环境打开HTML即可使用并可自定义CPU占用百分比与持续时长测试完成后关闭页面自动恢复避免长期高负载影响日常操作。已有718人学习下载。该工具虽小但针对CPU占用模拟场景提供了即开即用的完整实现读者既能快速上手进行压力测试也可基于HTML与JS代码理解CPU负载模拟原理自行调整参数或扩展出更复杂的性能测试脚本适用于日常调试、装机验收、教学演示及硬件散热评估等场景。1. Windows 刷 CPU 使用率工具一个可控的负载发生器工具名听着玩闹实际干的是正经活在 Windows 上制造可控的 CPU 高负载让散热压测、降压稳定性、虚拟机调度和脚本性能评估都有统一的压力来源。适合三类人装机后想验证散热和降频曲线的 DIY 用户模拟业务高峰的运维以及想确认自己多线程程序到底吃满几个核心的开发者。先把一个反直觉的结论放在这占用率不是“刷”出来的是忙等待时长与睡眠时长的比值算出来的同一份负载工具在物理机、笔记本和虚拟机里的读数可以差三倍而这些差异不解决后面所有压测结论都会失真。2. 两条实现路线批处理死循环与 C# 多线程忙等待负载工具的第一步是“让 CPU 真正忙起来”。Windows 上没有现成的压力测试命令行但原理很朴素——只要有一个线程在逻辑处理器上持续执行、不进入睡眠系统就会判定该核心处于忙碌状态。两条实现路线分别对应两个目标批处理最快跑通C# 能精确控制。先走通简单的再上可控的。2.1 批处理死循环单核打满的最小可运行方案创建一个idle_worker.bat内容只有三行echo off :loop goto loop这段代码让 cmd.exe 不停地在:loop和goto loop之间跳转永不退出。cmd.exe 自身是一个用户态进程它持续占用一个逻辑处理器的时间片任务管理器里对应核心的占用率会逼近 100%。再写一个burn.cmd负责按核心数拉起多个 workerecho off setlocal enabledelayedexpansion rem burn.cmd [核心数] - 默认打满4个逻辑核心 set /a cores4 if not %1 set /a cores%1 set /a mask1 for /L %%i in (1,1,%cores%) do ( start /affinity !mask! /high cmd /c call idle_worker.bat set /a maskmask*2 ) echo 已在 %cores% 个逻辑核心上启动负载进程。逻辑说明循环从 1 到 cores 逐个拉起子进程/affinity指定新进程运行在哪个逻辑核心上/high把进程优先级设为高。mask 从 1 开始每轮乘 2依次对应核心 0、1、2、3 的亲和掩码。批处理里set /a输出的是十进制整数而/affinity接受十六进制掩码因为这里每次都乘 2所以掩码永远是 2 的幂次十进制 1、2、4、8 和十六进制 1、2、4、8 数值恰好一致第 10 个核心的掩码 512 传进去对应的就是 0x200可以直接混用不需要手动换算。参数说明cores 指要打满的逻辑核心数不是物理核心数。在 4 核 8 线程的超线程处理器上cores8 才能把任务管理器总占用率刷到接近 100%。mask 每轮翻倍最终对应当前进程要绑定的那个核心这是批处理里最简单的核分配方式。运行burn.cmd 4任务管理器性能页会看到前四个逻辑核心各自冲到满格。这条路的局限也很明显只能打满不能指定占用率。想让 CPU 稳定在 60%批处理只能靠 ping 延迟、timeout 或随机 sleep 来“蒙”粒度粗糙到没法用于量化测试。它适合快速确认散热风扇有没有转、机器能不能扛住满载但做不了负载曲线测试。2.2 C# 多线程忙等待多核协同与进程级控制要精确控制占用率就得换成能操作线程的编译型程序。C# 在 Windows 上生态最省事用 .NET SDK 或 Developer PowerShell 里的 csc 都能编译。下面这个版本是“打满”思路的多核实现using System; using System.Diagnostics; using System.Runtime.InteropServices; using System.Threading; namespace CpuLoadSimulator { class Program { [DllImport(kernel32.dll)] static extern IntPtr GetCurrentThread(); [DllImport(kernel32.dll)] static extern IntPtr SetThreadAffinityMask(IntPtr hThread, IntPtr dwThreadAffinityMask); static void Main(string[] args) { int threadCount args.Length 0 ? int.Parse(args[0]) : Environment.ProcessorCount; for (int i 0; i threadCount; i) { int coreIndex i; Thread t new Thread(() { // 让线程只跑在指定的逻辑核心上 SetThreadAffinityMask(GetCurrentThread(), new IntPtr(1 coreIndex)); while (true) { } }); t.Start(); } Console.WriteLine($已启动 {threadCount} 个忙等待线程, 按任意键退出...); Console.ReadKey(); } } }逻辑说明Main 里按传入线程数创建 Thread每个线程先通过 SetThreadAffinityMask 绑定到1 coreIndex对应的逻辑核心再进入 while(true) 忙等待。GetCurrentThread 拿的是调用线程的句柄SetThreadAffinityMask 把它固定到指定的逻辑核心上。threadCount 默认取 Environment.ProcessorCount在超线程机器上就是逻辑处理器总数保证每个逻辑核都有线程在跑。编译方式dotnet new console -n CpuLoadSimulator建工程替换 Program.cs 后执行dotnet build -c Release用 csc 直接编也可以但我建议 Release 而不是 DebugDebug 版本里 JIT 和附加调试信息会带来额外开销让负载曲线不够平稳。参数说明threadCount 是启动的忙等待线程数建议等于逻辑处理器数明显小于逻辑核心数时会出现一部分核空闲。coreIndex 从 0 开始对应掩码 1 左移 coreIndex 位第 5 个线程绑定到掩码 0x10 的逻辑核心。若机器是 4 物理核 8 逻辑核绑定到逻辑核 0 和 1 的两个线程共享同一物理核的执行单元总占用率不会简单叠加这一点在第 4 章避坑里细说。到这里“打满”已经完成但从“打满”到“能指定百分比”还差一个关键算法——时间片分割。3. 可控负载的关键参数时间片分割、核心绑定与优先级3.1 时间片分割算法用“忙闲比”把占用率拉成指定值原理一句话一个固定周期内忙等待时间和睡眠时间各占多少决定了这段时间的平均占用率。周期取 100ms目标 60% 就是忙 60ms、空 40ms。代码如下替换上一章 while(true) 空循环即可using System.Diagnostics; using System.Runtime.InteropServices; [DllImport(winmm.dll)] static extern uint timeBeginPeriod(uint uMilliseconds); static void BurnWithTimeSlice(int percent, int intervalMs) { int busyMs intervalMs * percent / 100; int idleMs intervalMs - busyMs; Stopwatch sw new Stopwatch(); while (true) { sw.Restart(); while (sw.ElapsedMilliseconds busyMs) { // 忙等待: 把当前周期内的高占用时段耗完 } sw.Stop(); Thread.Sleep(idleMs); } }调用侧先执行timeBeginPeriod(1)把系统全局计时器精度从默认的 15.6ms 提到 1ms再创建 N 个线程每个线程传入 percent 和 intervalMs。逻辑说明busyMs 等于周期乘目标百分比忙等待段用 Stopwatch 计时到预定时长然后睡眠空闲段。Stopwatch 在 Windows 上底层走 QueryPerformanceCounter是微秒级精度不受 Sleep 分辨率影响而 Thread.Sleep(idleMs) 在 timeBeginPeriod(1) 之后才能把 40ms 睡成 40ms。参数说明intervalMs 取 100 的好处是每 1% 占用率对应 1ms便于脑内验算。interval 太短比如 10ms线程切换和 Stopwatch 调用的开销占比上升实际占用率会系统性偏高interval 太长比如 1000ms负载曲线会有肉眼可见的锯齿任务管理器里像在呼吸。我最常用的组合是 interval100、percent5090波动控制在 ±3 个点以内。补充一个很多人忽略的事timeBeginPeriod(1) 是全系统全局生效的会把所有进程的定时器精度都拉高直接后果是笔记本续航小幅下降。工具跑完退出影响不大要是做成常驻后台程序记得最终调用 timeEndPeriod(1) 恢复否则会干扰系统里其他程序的 Sleep 行为。3.2 线程亲和性把负载压到指定的逻辑核心上在多核机器上不设置亲和性Windows 调度器会把线程在不同核心之间来回搬运。表面看总占用率没差但线程迁移会破坏缓存热度负载曲线出现额外抖动更麻烦的是你无法确认“哪一个核心的真实压力是多少”。所以第 2 章里才把 SetThreadAffinityMask 放到线程开头SetThreadAffinityMask(GetCurrentThread(), new IntPtr(1 coreIndex));逻辑说明参数 dwThreadAffinityMask 的每个 bit 对应一个逻辑处理器bit 为 1 表示该线程可以被调度到这个处理器上只设一个 bit 就是把线程钉死在一个逻辑核上。注意必须在线程内部调用因为亲和性是线程级属性不是进程级属性虽然进程级有 ProcessorAffinity 可用但直接在 Thread 回调里调用 kernel32 更干净也省去 ProcessThread 与托管线程映射的麻烦。参数说明coreIndex 不要超过 63超过的话1 coreIndex会溢出64 逻辑核以上的机器要换用IntPtr(1L coreIndex)。另一个容易踩的细节是超线程逻辑核 0 和 1 共享同一个物理核的执行单元如果只刷核心 0 和核心 1物理核资源已经吃满但任务管理器总占用率只有 25%4 物理核场景这不是工具坏了是超线程折算的正常表现。3.3 优先级与 Windows 调度为什么“高”够用、“实时”是翻车现场负载线程默认优先级是 Normal会被同优先级的业务线程抢时间片负载曲线会被拉低。所以工具里通常要把进程优先级提到 HighProcess.GetCurrentProcess().PriorityClass ProcessPriorityClass.High;逻辑说明PriorityClass 影响进程内所有线程的基准优先级。High 对应线程优先级 15 级左右高于大多数普通应用低于 Windows 内核关键线程。设成 High 之后负载线程能稳定拿到调度优先权目标占用率更容易贴近设定值。参数说明还有个 Realtime 选项对应优先级 24 级。听起来更“狠”但副作用是可能压过键盘、鼠标输入设备的内核处理线程实际操作中很容易出现鼠标飘、ping 不通、任务管理器打不开最后只能硬重启。我的血泪经验是压测工具一律用 High不上 Realtime需要跟其他高优先级进程抢资源时用 ProcessThread.PriorityLevel 单独调负载线程而不是动整个进程。到这里可控负载的基本盘已经齐了时间片分割控制占用率、亲和性控制核心分布、优先级控制调度权重。接下来讲真正拉开差距的部分——同样是刷 CPU为什么有人刷出来是一条直线有人刷出来是一床心电图。4. 避坑与排查占用率虚低、读数不准和降频翻车这一章只记实际踩过的坑每条都按“现象 → 原因 → 解决”三段写按出现的频率排序。4.1 任务管理器 50% 之谜现象跑起来后任务管理器总占用率只有 50% 上下图形上不去但风扇已经在呼呼转。原因拆成两层。第一层线程数小于逻辑核心数Windows 调度器又把负载线程轮流分给多个核心每个核心瞬时占用都不满平均到总占用率就更低。第二层任务管理器“性能”页默认显示的是“总占用率”是所有逻辑核心忙闲比例的平均值单线程在任意时刻只能占住一个逻辑核心所以它最多把总占用率推到 1/N——N 是逻辑核心数。4 核机器单线程打满总占用率大约 25% 而不是 100%。解决先确认线程数等于逻辑核心数然后右键任务管理器性能页的 CPU 图把图形切换为“逻辑处理器”逐个核对每个逻辑核是不是都在跳。总占用率是一条直线但逻辑核有高有低说明没有做到线程均匀绑定逻辑核都是满格但总占用率只有 50% 多是超线程折算或节能状态引起的读数口径差异需要看下一节更底层的计数器。4.2 Sleep 睡出 15 毫秒和优先级被抢占现象设定 70% 占用率实际任务管理器只有 45%50%而且数值波动得厉害几十秒内上蹿下跳。原因有两个。第一个是定时器分辨率Windows 默认计时器精度是 15.6ms代码里 Thread.Sleep(1) 实际睡掉约 15ms忙 70ms 空 15ms忙占比从 70% 掉到 70/(7015)≈82%不对实际是睡眠时长被拉长忙占比显著低于设定值再叠加调度器其他线程的影响读数自然乱跳。这是 Windows 上写负载工具最经典的坑。第二个是优先级负载线程保持 Normal一旦有磁盘、网络等 IO 操作触发系统按优先级提升机制业务线程瞬时抢过高优先级线程的时间片负载曲线周期性塌陷。解决调用 timeBeginPeriod(1) 把全局计时精度提到 1ms忙等待段改用 Stopwatch 计量同时把进程 PriorityClass 设为 High。改完后实测 70% 目标的误差能压到 ±3 个点。还有一个常见做法是把空闲段做成动态补偿每个周期结束后用实际 elapsed 更新 busyMs公式是 busyMs clamp(busyMs (target - actual) * 0.2, 0, intervalMs)把这段放进循环里负载能在 20 秒左右收敛到设定值适合长时间稳定性测试。4.3 满载降频和虚拟机读数失真现象跑 100% 满载半个小时后占用率自己掉到 60%任务管理器里频率从 4.5GHz 降到 2.5GHz。原因温度墙或功耗墙被触发CPU 主动降频自保。负载工具本身没坏是散热能力不够。而降频反过来会压低占用率——CPU 在更短的时间内完成了同样的指令数系统统计出的占用比例反而下降。如果不看频率只看占用率极易误判“工具不稳定”。解决区分使用目标。做散热验证时100% 满载跑 20 分钟足够看温升曲线做长期稳定性测试时把目标定在 80%给 CPU 留出频率余量。监测频率和温度Windows 下可以用 OpenHardwareMonitor 这类读 SMBus 的程序或者笔记本厂商自带的性能监视工具。核心原则是看“频率 × 占用率”联动而不是只看一个数。另一个翻车现场在虚拟机里VMware/Hyper-V 中刷 100% 占用Guest 系统显示满了宿主机任务管理器却只有 20%——或者反过来Guest 只有 60%宿主机已经快满了。原因很简单虚拟 CPU 由 hypervisor 调度到物理核心上Guest 看到的是虚拟 CPU 自己的统计跟物理核心真实负载没有直接关系Hyper-V 还会在宿主机多个逻辑处理器间动态迁移虚拟 CPU。所以虚拟机环境里要用宿主机计数器实测为准如果目标是验证宿主机压力直接在宿主机上跑工具别隔着 Guest 读数。5. 验证负载真实性的三个手段性能计数器、核心分布和频温联动工具做好了怎么确定不是“看起来 100%”而是真的压到位我一般用三个手段交叉验证这三件事能暴露任务管理器视图看不到的问题。第一用性能计数器校准读数。任务管理器的 CPU 百分比来自% Processor Time它基于时钟中断折算受节能状态影响更接近真实功耗的是% Processor Utility它考虑了频率和空闲状态切换。PowerShell 这样采样$counter \Processor Information(_Total)\% Processor Utility $sample (Get-Counter -Counter $counter -SampleInterval 1 -MaxSamples 10).CounterSamples $vals $sample | ForEach-Object { $_.CookedValue } $avg ($vals | Measure-Object -Average).Average Write-Host 10秒平均 CPU Utility: $avg%逻辑说明CounterSamples 的 CookedValue 才是格式化后的百分比值10 个每秒采样平均后能过滤瞬时波动。SampleInterval 设 1 秒MaxSamples 设 10得到 10 秒窗口的均值要分钟级平滑度把 MaxSamples 改成 60 即可。跑负载工具时把这个脚本挂旁边如果 Utility 读数和任务管理器差超过 5 个点说明线程分布或定时器精度有问题。第二检查核心分布是否均匀。注意不要只盯 _Total在性能监视器里添加多实例计数器看每个逻辑核心的 Utility。可以加个表格做对比计数器含义用途% Processor Time基于中断的忙时占比任务管理器同源快速观测趋势% Processor Utility考虑频率与空闲状态的瞬时利用率校准负载读数% Privileged Time内核态时间占比判断负载是否异常转入内核态如果某些逻辑核心长期 0% 而另一些 100%说明亲和性设置没全覆盖如果所有核都在跳但没有一个稳定在目标值附近多半是 Sleep 精度问题没根治。第三频温联动记录。同时记录频率和占用率负载工具跑 30 分钟观察是否出现占用率仍高但频率下滑的段——那就是散热瓶颈。这个习惯帮我找回过两台“跑分正常但满载降频”的笔记本。从那以后我每次给机器或脚本做压测前都强制先跑一遍这三个验证手段再开始记录数据。坑都是踩过才长的记性第一版工具用了默认定时器精度读数偏差大到我不敢信后来养成习惯跑任何负载工具之前先挂 perfmon再决定要不要信任务管理器。希望帮到你。本文还有配套的精品资源点击获取