去年冬天帮同事收拾一台笔记本,风扇声隔着两张桌子都听得见。打开任务管理器一看,CPU 总占用才 9%,一堆进程明明在打瞌睡,可频率稳稳顶在 4.1 GHz 下不来,封装功耗在 35 W 上下晃,电池撑不到两个半小时。问题很典型:Windows 只会把完全空闲的逻辑处理器放进低频,对"半忙不忙"的进程基本不管。后来我把几个后台进程挨个右键设成效率模式,频率掉到 2.0 GHz 附近,封装功耗落到 12 W 上下,风扇从"吹风机"变成了"听不见",同一块电池多跑了一个多小时。
这篇东西想聊的就是这件事:Windows 里的进程效率模式到底动了什么、哪些进程开了立刻见效、哪些进程开了会翻车、怎么把设置持久化下来、以及最关键的一点——功耗降了多少、能效比提升了多少,该怎么量出来,而不是靠感觉。内容偏向实操,适合两类人:一类是想让笔记本续航变长、风扇变安静的普通用户;另一类是开发/运维,机器上常年跑着一堆同步客户端、下载器、中间件、上位机采集程序,想让这些"吃电不吃性能"的进程老实待在低功耗区。不需要你懂内核调度,但读完你应该能自己判断一个进程该不该开、开了之后怎么验证。
1. 效率模式到底改了什么:从 Power Throttling 到 EcoQoS 的调度逻辑
1.1 任务管理器里那个叶子图标,背后其实是三件事同时发生
很多人以为"效率模式"就是给进程降频,这个理解只对了一半。你在任务管理器里点下"效率模式",实际上是三件事一起发生:
第一件事是优先级下降。进程的优先级类会被拉到最低档(Idle 级别附近),调度器在有其他线程等着跑的时候,会优先让别人先跑。这一步是任务管理器自己顺手做的,不是 API 的必然结果。
第二件事是打上 Power Throttling 标记。这是 Windows 10 时代就引入的机制,API 层面就是SetProcessInformation配合ProcessPowerThrottling这个信息类,把PROCESS_POWER_THROTTLING_EXECUTION_SPEED这一位置起来。它的含义是"这个进程不需要跑在最高性能状态",系统可以把它限制在较低的性能档位上。
第三件事是EcoQoS(Eco Quality of Service)生效。这是效率模式真正有意思的部分。带了这个标记的线程,会被调度器引导到"能效核"上去跑;在没有大小核区分的 CPU 上,则倾向于让它跑在尽可能低的频率点上。
把这三件事分开看,很多事情就说得通了。比如为什么有些进程设了效率模式之后 CPU 占用百分比反而变高了——因为它跑在低频核上,同样的工作量自然要占更多"百分比"。任务管理器那个 CPU 占用率是相对当前频率算的,不是绝对算力。
| 机制 | 作用粒度 | 主要效果 | 典型局限 |
|---|---|---|---|
| 优先级下降 | 进程 | 让出调度机会给其他线程 | 只影响排队顺序,不改频率 |
| Power Throttling | 进程/线程 | 限制在较低性能档位 | 核心空闲时收益有限 |
| EcoQoS | 线程 | 引导到能效核或最低频率 | 对延迟敏感的链路不友好 |
| 电源计划 | 整机 | 限制最大处理器状态 | 一刀切,前台的活也一起受影响 |
1.2 为什么"降频"不是重点,"调度到哪颗核"才是重点
我见过太多人把这件事理解成"给进程降频",然后实测发现省不了多少电,就下结论说效率模式是噱头。问题出在测量场景上。
现在的消费级 CPU 基本都是线性功耗区域工作的:频率从 2 GHz 拉到 4 GHz,性能大概翻一倍,但功耗往往要翻两倍多。也就是说,一个只用了 5% CPU 的进程,如果它被安排在一颗高频运行的大核上,它实际消耗的能量远超它完成的工作所需的能量。效率模式的价值不在于"让这个进程慢一点",而在于把它从昂贵的位置挪到便宜的位置。
在 Intel 12 代之后的大小核平台上,这个效果最直观:同一个同步进程,之前可能抢占大核的时间片,设成效率模式之后被丢到能效核上,大核可以更长时间地进入深度睡眠。AMD 平台和老一点的 Intel 平台没有大小核之分,EcoQoS 的落点就变成"最低可用频率档",收益会打折扣,但依然存在。
这里要引入一个真正的衡量指标:能效比 = 完成的工作量 / 消耗的能量。注意它和"省电"不是一回事。一个进程设了效率模式之后跑得更慢、但功耗降得更多,那能效比是提升的;如果它跑得慢了一半、功耗只降了两成,那能效比是下降的。后面第 4 节我会专门讲怎么把这两个数字都测出来,然后算这笔账。
1.3 它和电源计划、节能模式完全是两码事
我经常听到"我电源模式已经调到最佳能效了,还需要开效率模式吗"这种问题。需要,因为这两个东西的粒度差了三个数量级。
电源模式是整机级别的开关。你切到"最佳能效",Windows 会去限制最大处理器状态、调整散热策略、改变核心停放行为,影响的是所有进程,包括你正在打字的这个输入框。副作用就是前台交互也会跟着变钝。
效率模式是单个进程级别的开关。它只影响你选中的那个进程,前台游戏该满血跑还是满血跑。粒度越细,误伤面越小,这也是我更推荐用效率模式而不是全局压频的原因。
还有一种容易混淆的状态:任务管理器里显示"已挂起"的进程。那是 UWP 应用的冻结机制,进程被整个停掉了,一点 CPU 都不占,和效率模式完全是两回事。效率模式下的进程是活的,还在跑,只是跑得"省"。
提示:如果你只想快点看到风扇变安静,先把电源模式切到"最佳能效",再对三五个最吵的后台进程手动开效率模式。两个动作叠加,通常十分钟内就有体感。
2. 哪些进程该开、哪些开了会出事
2.1 收益最明显的一类:后台常驻、同步与下载
判断标准很简单:这个进程有没有人在等它的结果?没人在等,那它就适合开效率模式。
按我这几年的经验,收益最明显的是这几类:
- 云盘同步客户端(OneDrive、坚果云、各类企业网盘客户端)。它们大部分时间在做哈希校验和后台拉取,用户根本感知不到速度差异,但它们的轮询频率往往很高,是把 CPU 从深度睡眠里反复拽出来的常客。
- 下载器。跑满带宽的时候 CPU 占用看着不低,其实全是协议栈和写盘的开销,开效率模式之后下载速度几乎没有变化,这是我实测下来性价比最高的一类。
- 聊天与邮件客户端的常驻进程。注意是"常驻进程",不是"你正在打字的那个窗口进程"。有些客户端是多进程架构,要对准它的后台服务进程下手(进程名往往带 helper、service、sync 之类的后缀),主界面进程别碰。
- 软件更新器、驱动检查工具、遥测上报进程。这类东西最喜欢在后台偷偷跑,设成效率模式基本没有副作用。
- 浏览器里"没在用"的那一堆渲染进程。浏览器是多进程架构,每个标签页一个渲染进程。把不活跃标签页的渲染进程设成效率模式是相当有效的做法,但浏览器的主进程、GPU 进程、网络进程千万不要碰,一碰就是大面积掉帧。
一个很实用的判断方法:在任务管理器"详细信息"标签页里,把"电源使用情况"这一列打开。Windows 11 会给出"非常低/低/中/高"的分级,那些长期显示"中"以上、但 CPU 占用率很低的进程,就是效率模式的理想目标。这类进程的共同特征是"轻度但高频"——活儿不多,但醒得勤,每次醒来都让 CPU 跳一次频。
2.2 开了大概率翻车的:实时音频、前台交互、编译与渲染
反过来,只要一个进程的产出"有人在实时等",就别给它开效率模式。
音频链路是第一大雷区。只要你的机器上跑着 ASIO 声卡、DAW、直播推流软件、或者任何对音频缓冲区有要求的程序,把相关进程设成效率模式之后,最常见的症状是爆音和咔哒声。原因不是"算力不够",而是调度抖动变大了:线程被从一颗核迁到另一颗核、频率来回切换、唤醒延迟不稳定,音频缓冲区就在这些不确定的间隙里被掏空了。
游戏进程也不建议开。帧率平均值可能看不出什么变化,你看帧生成时间(frame time)那条曲线就知道,会明显变毛。游戏是最典型的不看平均值、只看最坏情况的负载。
编译、渲染、视频导出这类批处理任务,开不开取决于你要什么。如果你在插着电、想把活赶紧干完,别开。如果你在电池上、愿意用 20% 的时间换 30% 的电,那可以开。这就是第 1 节说的能效比权衡。
数据库和中间件要单独说。开发机上常年挂着的 Elasticsearch、Redis、MySQL 这类服务,空闲的时候开效率模式没问题,一旦你要跑压测或者导入大批量数据,先把它们关掉,否则你会以为是代码写慢了。
| 进程类别 | 建议 | 主要风险 |
|---|---|---|
| 云盘同步、下载器 | 开 | 几乎无 |
| 聊天/邮件常驻服务进程 | 开 | 消息推送延迟略增 |
| 浏览器后台标签渲染进程 | 开 | 切回标签时首帧略慢 |
| 浏览器主进程/GPU 进程 | 不开 | 全局掉帧 |
| 音频、直播、录屏 | 不开 | 爆音、丢帧 |
| 游戏 | 不开 | 帧生成时间抖动 |
| 编译、渲染、导出 | 看情况 | 任务耗时变长 |
| 开发机空闲中间件 | 看情况 | 压测数据失真 |
2.3 混合架构 CPU 上的额外收益,以及一个经常被忽略的替代方案
如果你用的是 Intel 12 代以后带大小核的处理器,效率模式的收益会比老平台高一截,因为线程真的被挪到了物理上更省电的核心上。这时候你会发现一件有意思的事:开了效率模式的进程,在任务管理器里显示的 CPU 占用可能没降多少,但整机功耗明显下来了。
但反过来说,如果你的目标只是"别让某个后台进程抢大核",其实还有一个比效率模式更硬核的方案:CPU 亲和性(affinity)。把进程硬绑到某几颗能效核上,调度器连考虑的机会都没有,抖动比效率模式更小、更可预测。代价是灵活性差,而且绑核需要更谨慎——绑错了会造成单核打满、其他核围观。
我的习惯是:日常、临时、不确定的进程用效率模式;长期固定跑的后台服务用亲和性绑核。前者不需要重启进程就能生效,后者一旦配好就非常稳定。
还有一个容易被忽略的细节:某些主板的 BIOS 里可以关闭能效核,或者调整 P/E 核的调度偏好。我不建议在没有明确需求的情况下去动 BIOS 里的这些设置,操作系统层面的调度策略已经做了大量适配,手动干预常常是负收益。
3. 手动开启的完整操作链路
3.1 任务管理器右键那一下,以及它为什么经常"自己关掉"
最直接的做法:任务管理器 → 详细信息标签页 → 找到目标进程 → 右键 → 效率模式。Windows 11 里打开之后,进程名旁边会出现一片小叶子。
这一步有几个前提条件,很多人卡在这里却不知道原因:
- 任务管理器需要以管理员身份运行,否则给高权限进程设置时会失败,菜单项是灰的或者点了没反应。
- 受保护进程不给设。反作弊保护的游戏进程、部分系统关键进程、带数字签名的安全组件,都会拒绝这个请求。
- 设置不持久。这是最要命的一点。效率模式的标记只存在于当前进程实例上,进程退出重开就没了,系统重启更不用提。
- 应用可以自己改回去。有些程序在启动或者检测到特定状态时,会主动调用提优先级的 API 把自己拉回正常档位,你会发现叶子图标过一会儿自己消失了。
最后一条是新手最容易困惑的:"我明明设了,怎么过十分钟就没了?"这不是 bug,是那个程序在跟你对着干。
3.2 用 PowerShell 批量处理与定时兜底
手工点几十个进程显然不现实,直接上脚本。核心是调用SetProcessInformation,PowerShell 里用Add-Type内联一段 C# 就能搞定:
# 以管理员身份运行 Add-Type @" using System; using System.Runtime.InteropServices; public class EcoQoS { [DllImport("kernel32.dll", SetLastError = true)] static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId); [DllImport("kernel32.dll", SetLastError = true)] static extern bool CloseHandle(IntPtr hObject); [DllImport("kernel32.dll", SetLastError = true)] static extern bool SetProcessInformation(IntPtr hProcess, int ProcessInformationClass, ref PROCESS_POWER_THROTTLING_STATE ProcessInformation, int ProcessInformationSize); [StructLayout(LayoutKind.Sequential)] public struct PROCESS_POWER_THROTTLING_STATE { public uint Version; public uint ControlMask; public uint StateMask; } const int ProcessPowerThrottling = 4; const uint EXECUTION_SPEED = 0x1; const int PROCESS_SET_INFORMATION = 0x0200; public static bool Set(int pid, bool enable) { IntPtr h = OpenProcess(PROCESS_SET_INFORMATION, false, pid); if (h == IntPtr.Zero) return false; var st = new PROCESS_POWER_THROTTLING_STATE(); st.Version = 1; st.ControlMask = EXECUTION_SPEED; st.StateMask = enable ? EXECUTION_SPEED : 0; bool ok = SetProcessInformation(h, ProcessPowerThrottling, ref st, Marshal.SizeOf(st)); CloseHandle(h); return ok; } } "@ $allowList = @('OneDrive', 'Dropbox', 'Teams', 'Thunder', 'BaiduNetdisk') Get-Process -Name $allowList -ErrorAction SilentlyContinue | ForEach-Object { $r = [EcoQoS]::Set($_.Id, $true) "{0,-24} PID={1,-6} {2}" -f $_.ProcessName, $_.Id, $(if ($r) { 'OK' } else { 'FAILED' }) }跑之前有几个点要交代清楚。
首先,这段脚本只做 Power Throttling 标记,不会改优先级。任务管理器右键那一下是额外把优先级也降了。如果你想让脚本行为完全对齐任务管理器,再补一行:
$p = Get-Process -Id $pid $p.PriorityClass = 'Idle'其次,OpenProcess里的0x0200是PROCESS_SET_INFORMATION,这是SetProcessInformation要求的最低权限。如果你要往系统进程(比如各种 Service)上设,脚本必须以管理员身份运行,否则OpenProcess直接返回 0,脚本会老老实实打印 FAILED。这个 FAILED 是有价值的信号,别忽略它,它通常说明权限不够或者进程受保护。
第三,StateMask传 0 就是关闭。所以你要写"一键恢复"脚本,把$true改成$false就行,不需要重启进程。
3.3 定时任务兜底:让设置在进程重启后自动回来
因为效率模式不持久,最省心的做法是挂一个计划任务,登录时触发 + 每隔十几分钟重复一次,把允许清单里的进程重新扫一遍。进程没重开就重复设置(幂等,无害),重开了就自动补上标记。
$action = New-ScheduledTaskAction -Execute 'powershell.exe' ` -Argument '-NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File C:\Tools\EcoQoS.ps1' $t1 = New-ScheduledTaskTrigger -AtLogOn $t2 = New-ScheduledTaskTrigger -Once -At (Get-Date) ` -RepetitionInterval (New-TimeSpan -Minutes 15) $principal = New-ScheduledTaskPrincipal -UserId $env:USERNAME -RunLevel Highest Register-ScheduledTask -TaskName 'EcoQoS-Keeper' ` -Action $action -Trigger $t1, $t2 -Principal $principal注意-RunLevel Highest这一项,没有它脚本就跑在普通权限下,对很多目标进程会直接失败。
注意:定时兜底是一把双刃剑。如果你的允许清单里混进了某个自己会提优先级的程序,脚本每 15 分钟把它按下去一次,程序又弹回来,两方拉锯的过程中会额外产生一点调度开销。所以允许清单要短、要准,别图省事写通配符。
如果你不喜欢自己维护脚本,Process Lasso 这类进程管理工具新版本里也提供了电源相关的控制项,能省掉不少体力活。但要提醒一句:不同版本菜单里的叫法和位置差异不小,以你机器上实际装的那个版本为准,别照着旧教程找菜单位置。
3.4 在自己的程序里主动申请:给做工具软件的人
如果你是开发者,写的是那种"常驻后台、干活不急"的程序——比如各种上位机采集程序、同步服务、监控上报客户端——那主动申请效率模式是一种礼貌。用户不一定会自己去任务管理器里给你点那一下,但你可以自己举手。
C# 里的写法跟上面 PowerShell 里的那段 C# 完全一致,SetProcessInformation没有任何托管 API 封装,必须 P/Invoke。启动阶段调用一次就够了,进程级别的标记会持续到进程退出。
如果是线程级别的精细控制,还有SetThreadInformation配合ThreadPowerThrottling,只把某几个后台工作线程压下去,主线程和 UI 线程保持正常。这个粒度在写"采集 + 界面"二合一的程序时特别有用:采样线程可以省,界面线程不能省。
顺便提一个我认为被严重低估的标志位:PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION(值 0x4)。很多采集类程序为了让自己的定时更准,会调用timeBeginPeriod把系统定时器精度拉到 1 ms。这个动作会让整个 CPU 无法进入深度睡眠状态,代价是全局的,非常昂贵。把这一位设上,可以让系统忽略你的高精度定时器请求。文档里对它的描述比较简短,具体行为随系统版本有差异,建议实测后再上生产。
4. 功耗到底降了多少:一套能复现的测量方法
4.1 先想清楚你要测的是哪一层
"功耗降了多少"这句话本身是模糊的,因为至少有三种量法,量出来的数字差很远。
软件层看的是进程自己的行为:CPU 时间、% Processor Performance(相对于基频的性能百分比)、线程唤醒次数。这一层最容易测,也最容易骗人,因为它不包含"因为频率被拉高而多消耗的能量"。
CPU 封装层看的是 RAPL 计数器给出的封装功耗,也就是 CPU 这颗芯片自己吃了多少瓦。这一层的数字最能反映效率模式的作用,因为效率模式影响的正是 CPU 的调度和频率。
整机层看的是墙插功率计或者电池放电速率。这一层最贴近用户体感,但噪音也最大,因为屏幕、内存、硬盘、风扇、主板 VRM 的损耗全在里面。在一台轻薄本上,CPU 封装功耗从 22 W 降到 13 W,整机可能只从 33 W 降到 24 W,因为屏幕就固定吃掉 6、7 W。
我的建议是三层都测,但用 CPU 封装层的数字来判断效率模式有没有生效,用整机层的数字来判断值不值得。
| 观测层 | 典型工具 | 优点 | 误差来源 |
|---|---|---|---|
| 软件层 | 任务管理器、perfmon | 随时可看 | 百分比随频率浮动,不反映能耗 |
| CPU 封装 | HWiNFO 等硬件监控 | 直接反映芯片功耗 | 需要 RAPL 支持,采样有延迟 |
| 整机 | 墙插功率计、电池报告 | 最贴近真实体感 | 屏幕/外设恒定损耗稀释差异 |
4.2 用 powercfg 和 perfmon 抓数据的具体命令
Windows 自带的工具组合其实够用,只是藏得比较深。
电池续航相关的三份报告,先跑起来:
powercfg /batteryreport /output $env:USERPROFILE\Desktop\battery.html powercfg /sleepstudy /output $env:USERPROFILE\Desktop\sleepstudy.html powercfg /energy /duration 60 /output $env:USERPROFILE\Desktop\energy.html/batteryreport给的是容量和充放电历史,/sleepstudy给的是现代待机期间的耗电曲线,/energy会跑 60 秒的系统诊断并列出"谁在浪费电"。这三份报告里,/energy的输出最像一份体检单,它会点名那些把 CPU 从低功耗状态里拽出来的进程。
还有一个查"谁在阻止系统休息"的神器:
powercfg /requests跑完什么都不显示,说明当前没有程序在阻止熄屏或睡眠;有输出的话,它会分成"显示""系统""离开模式"几类,把肇事进程的路径列出来,非常直观。
如果要长时间连续采样,用typeperf更合适:
typeperf "\Processor Information(_Total)\% Processor Performance" ` "\Processor Information(_Total)\Processor Frequency" ` "\Energy Meter(*)\Power" ` -si 2 -sc 60 -o C:\Temp\eco.csv这里有个中文系统的坑:性能计数器的名字是本地化的。上面那串英文名在英文系统上没问题,中文系统上往往要换成对应的中文名(比如"处理器信息")。最稳的做法是先跑typeperf -qx把本机所有计数器名导出来,或者直接打开性能监视器,用"添加计数器"的图形界面确认实际名称,再抄进脚本。我第一次用的时候在这个坑里蹲了半小时,一直以为是权限问题。
另外\Energy Meter(*)\Power这组计数器不是每台机器都有,它依赖固件和驱动的支持。如果没有,就退回到% Processor Performance结合硬件监控软件读封装功耗。
4.3 我实测的一组对照数据与解读
下面这组数据来自我那台 12 代大小核的轻薄本,电池供电,屏幕亮度固定 50%,关掉无线网络外的所有外设,每个场景先跑 60 秒预热再取 5 分钟稳定段的平均值,重复三轮取中位数。负载是 8 个后台同步类进程同时做文件哈希和上传。
| 场景 | 平均频率 | CPU 封装功耗 | 整机功耗 | 任务耗时 |
|---|---|---|---|---|
| 空载基线 | 2.6 GHz | 6.8 W | 11 W | — |
| 负载,未开效率模式 | 3.6 GHz | 22 W | 31 W | 100% |
| 负载,开效率模式 | 2.1 GHz | 13 W | 21 W | 118% |
光看这三个数字可能觉得"就是慢了 18%,省了 9 W"。真正有价值的是把它们换算成能效比。
能耗 = 功耗 × 时间。设未开效率模式的耗时是 T:
- 未开:22 W × T = 22T
- 开:13 W × 1.18T = 15.34T
能耗降低了 (22 − 15.34) / 22 ≈30%。
能效比 = 单位能耗完成的工作量,与"功耗 × 时间"成反比:
- 未开:1 / 22T
- 开:1 / 15.34T
提升幅度约为 22 / 15.34 − 1 ≈43%。
也就是说,这个场景下你付出的代价是任务时间变成原来的 1.18 倍,换来的是每完成同样的工作量少花三成能量、能效比提升四成多。如果这是一个晚上挂着跑的同步任务,这个交换非常划算;如果这是你盯着进度条等结果的编译任务,那就不划算。同一个机制,换个场景结论完全相反,这就是为什么我一直强调要先想清楚"有没有人在等结果"。
4.4 测量本身的坑:为什么你的数据可能是假的
这部分是干货里最有价值的部分,因为大部分人第一次测出来的数字都是错的。
别用任务管理器的 CPU 百分比当功耗指标。它是相对于当前频率的占用率,频率变了这个数字就失去了可比性。开效率模式之后占用率反而升高是常事,不代表更费电。
屏幕亮度是最大的干扰变量。我把亮度从 100% 降到 60%,整机功耗直接掉了 5 W 左右,比刚才那个效率模式场景省得还多。测量期间亮度必须锁死。
后台的 Windows Update、Defender 扫描、索引服务是第二大干扰。测之前先把这些停掉或者等它们跑完,否则你的数据会被完全污染。
别用单次测量下结论。温度影响风扇曲线,风扇曲线影响功耗,功耗影响温度,这是个带滞后的反馈环。取稳定段、多轮取中位数是最低要求。
电池放电速率受电池老化和电量区间影响。同一个负载在 90% 电量和 30% 电量下的放电表现可能不一样,尽量在同一电量区间测。
取平均之前先扔掉前 30 秒。负载刚起来的时候频率会冲高,这段数据不代表稳态。
5. 踩坑记录:开了效率模式反而更卡、更耗电的情况
5.1 进程自己把优先级改回去
前面提过,叶子图标会自己消失。我认真追过一次:某个云盘客户端在检测到"正在上传大文件"时,会主动调用提优先级的接口把自己拉回正常档位。它的逻辑可以理解——保证上传速度——但结果是它每隔几分钟就把自己从低功耗区拽出来一次。
对应的排查方法很简单:写一个每 30 秒采样一次的监控脚本,记录目标进程的优先级类和叶子图标状态,跑一两个小时看趋势。如果发现规律性的"掉叶子",基本可以确认是应用自己在改。
应对方式有三条:一是接受它,只在不传文件的时候开;二是用定时任务兜底,把它反复按回去(有拉锯开销);三是换一个不这么激进的同步方案。
5.2 延迟敏感链路被打散:音频爆音、串流丢帧、游戏掉帧
我踩过最难受的一次,是把一个音频相关的后台进程设成了效率模式,结果在直播里出现了间歇性爆音,观众反馈之后我才发现是自己两天前设的。查日志什么都没查到,因为系统层面一切正常,只是调度抖动变大了。
这件事让我总结出一条规律:实时性看的是最坏情况,不是平均值。效率模式对平均值的影响往往是温和的,但它增加了线程迁移、频率切换和唤醒延迟的不确定性,这些统统体现在"最坏情况"那一端。所以音频、直播、游戏这条线上的所有进程,一律不碰。
5.3 一次完整的排查链路复现
去年有台机器出现"续航突然变差",我完整走了一遍定位流程,这里把链路复现出来,你可以照着走。
第一步,看放电曲线。powercfg /sleepstudy生成的报告里,如果看到放电速率在空闲时也维持在较高水平、且曲线呈阶梯状,说明有周期性唤醒。
第二步,查谁在阻止。powercfg /requests,确认不是某个程序在阻止熄屏或睡眠。
第三步,切排序口径。任务管理器"详细信息"标签页里,把排序改成按"电源使用情况"或者"CPU 时间"排,而不是按占用率排。这一步能立刻把那些"占用率低但醒得勤"的进程揪出来。
第四步,连续采样。用typeperf记录% Processor Performance和频率,采样间隔 2 秒,跑 10 分钟。
第五步,上重型武器。如果软件层看不出问题,用 Windows Performance Recorder 抓一段 30 秒的 trace,再用 Windows Performance Analyzer 打开,重点看 CPU 频率曲线和线程调度视图。
最后定位到的原因:一个每 5 秒轮询一次的温度采集程序。它在任务管理器里的 CPU 占用只有 0.3%,看起来完全无害,但它每次唤醒都会把一颗核心从深度睡眠状态拽出来,导致 CPU 封装功耗长期卡在 12 W 降不下去。给它开了效率模式之后,唤醒时不再触发频率冲高,封装功耗回落到 7 W 附近。
这个案例和"极低功耗无线温度监测上位机"这类场景高度重合。做这类程序的同行要注意:轮询频率不是越高越好,5 秒一次的轮询在软件层几乎不花钱,在功耗层可能比你想的贵得多。
5.4 和虚拟化、容器混用时的注意点
开发机上常见的一堆后台进程,处理原则不太一样。
WSL2 和 Hyper-V 在宿主机上表现为一个吃内存的大进程。如果你只是挂着不用,给它开效率模式确实能省电,但虚拟机内部的响应会变钝,因为宿主机给的调度时间片本身就被压缩了。
容器方案的后台进程(各种 backend、daemon)同理:挂机可以开,一旦你要在里面跑测试或者构建,先关掉。
要特别记住一点:宿主机的效率模式设置不会穿透到虚拟机内部。你在宿主机把虚拟机进程设成效率模式,等价于"给这台虚拟机的整体配额打折",而不是"虚拟机里的某个进程变省电了"。这两个是完全不同的事情。
5.5 权限与被保护进程的边界
最后一条经验:不要对系统关键进程和带保护机制的进程使用效率模式。
一是多半会失败(权限或保护机制拒绝),二是万一成功了反而可能带来奇怪的行为,比如某些服务的看门狗超时、某些驱动配套进程响应变慢。这类进程本来就已经被系统妥善管理了,不需要你操心。
判断标准很实用:任务管理器里右键看不到"效率模式"这个菜单项的,就别想办法绕过去设置它。
6. 把它做成长期方案:分层策略、兜底与回滚
6.1 一张可以直接照抄的分层策略表
这几年折腾下来,我基本固定成这套分层策略,你可以直接抄:
| 进程类别 | 效率模式 | 附加动作 |
|---|---|---|
| 云盘同步、下载器 | 开 | 定时任务兜底 |
| 聊天/邮件常驻服务进程 | 开 | 无 |
| 软件更新器、遥测进程 | 开 | 无 |
| 浏览器后台标签渲染进程 | 开 | 主进程/GPU 进程排除 |
| 音频、直播、录屏 | 不开 | 如需省电改绑核 |
| 游戏、前台交互程序 | 不开 | 无 |
| 编译、渲染、导出 | 按需 | 电池时开,插电时关 |
| 开发机中间件(空闲) | 按需 | 压测前必关 |
| 虚拟机/容器后台 | 按需 | 挂机开,干活关 |
| 系统关键进程 | 不开 | 别碰 |
这张表的核心逻辑就一句话:有没有人在等它的结果。有,就不开;没有,就开。
6.2 定时任务加允许清单的组合写法
把第 3.2 节的脚本落成文件,配上允许清单,再挂上第 3.3 节的计划任务,整套就闭环了。我建议在脚本里加两样东西:一个日志文件,和一段失败重试。
$log = 'C:\Tools\EcoQoS.log' $stamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss' Get-Process -Name $allowList -ErrorAction SilentlyContinue | ForEach-Object { if ([EcoQoS]::Set($_.Id, $true)) { Add-Content $log "$stamp OK $($_.ProcessName) $($_.Id)" } else { Add-Content $log "$stamp FAIL $($_.ProcessName) $($_.Id)" } }日志不是为了好看。当你怀疑"某个进程的叶子怎么老是掉"的时候,翻一下日志就能看出来是脚本没设上(权限问题)、还是设上了之后被程序改回去了(拉锯)。这两种情况的应对方式完全不同。
6.3 出问题了怎么一键回滚
效率模式的可爱之处在于它非常好回滚,因为它不改任何持久化配置。
最省事的回滚是重启——所有标记随进程消失。但如果你不想重启,可以跑一遍关闭脚本,把$true改成$false扫一遍允许清单。再退一步,一个个右键取消也花不了两分钟。
如果你还挂了计划任务,记得把它停掉,否则你刚关完,15 分钟后它又给你按回去了:
Unregister-ScheduledTask -TaskName 'EcoQoS-Keeper' -Confirm:$false万一你顺手改过注册表或者组策略(比如为了全局关闭电源节流,去动了电源管理相关的策略项),那就要把原值改回去,然后跑一次gpupdate /force让策略刷新。动这两处之前一定要先把原值抄下来,这类改动不像效率模式那样重启就恢复,很容易忘。
6.4 什么时候该放弃效率模式,改用别的办法
最后说一个反直觉的结论:如果你追求的是"续航变长",效率模式通常不是收益最高的那一项。
在我的机器上,效率模式在整机层面带来的降幅大概是 3% 到 8%,取决于负载类型。而屏幕亮度从 100% 降到 60%,能省 20% 上下;把后台的自动更新和索引服务管理好,又能省一截;如果机器支持现代待机,把合盖后的唤醒源清干净,省得更多。
效率模式真正不可替代的价值有两个:一是让风扇变安静,这个体感提升是立竿见影的,因为它直接压住了 CPU 的频率冲高;二是让那些"轻度但高频"的后台进程不再破坏 CPU 的深度睡眠,这部分收益在插电的台式机上不明显,在电池上非常明显。
我个人的用法是:效率模式只用在"明确知道没人在等结果"的那几个进程上,允许清单常年保持在十个以内,同一个进程只要出现过一次异常(音频爆音、切回标签卡顿、同步变慢),立刻从清单里移出去,不再尝试。清单短一点、稳一点,比清单长、天天出幺蛾子要好得多。
真要验证有没有效果,别信感觉,跑一次 4.3 节那种对照测量,把封装功耗和任务耗时两个数字记下来,算一遍能效比。数字漂亮就留着,数字难看就撤掉,这件事没什么好纠结的。