开启Windows进程效能(效率)模式,降低功耗大幅提升能效比

Windows11的22H2更新引入了效率模式,该模式通过自动调整处理器时间和CPU速度来节省能源,延长电池续航,降低风扇噪音。开发者可以利用API将进程设置为低功耗状态,适合后台服务和无高性能需求的任务。通过SetProcessInformation()和SetThreadInformation()函数,可以改变进程/线程的电源管理限制策略,以启用或禁用效率模式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在最近的Windows 11 22H2中,新增了一个被称为“效率模式”(Efficiency Mode)的功能,启用后操作系统将自动分配处理器时间片并适当地调整CPU时钟速度,从而提高能源效率/延长电池续航,减少风扇噪音和电源损耗。微软鼓励开发者使用此功能提高进程效能。

如下图所示,CPU的速度越快,性能越强,但功耗却呈指数级增长。这种高功耗会导致笔记本设备电池续航尿崩、温度飙升和更吵的风扇,而并非所有任务都需要高性能。

CPU功耗和频率

功能概念

进程和线程关联服务质量(QoS),在Win10 21359 中新增的 EcoQoS 状态对没有显著性能和延迟要求的工作负载非常有效。开发者可调用 API 来将其进程和线程注明为此状态,其余的由 Windows 负责。

适用场景

优先考虑节能的后端服务、程序更新、同步引擎、索引等,或者希望程序在后台工作时不那么过多的去占用计算机性能资源时。

使用方法

通过SetProcessInformation()SetThreadInformation()函数更改相关进程/线程PROCESS_POWER_THROTTLING_STATE,并将其中ControlMask和StateMask成员配置为PROCESS_POWER_THROTTLING_EXECUTION_SPEED

特别注意

以上两个API均需要相关句柄拥有PROCESS_SET_INFORMATION权限。

若使用GetCurrentProcess()获得的自身伪句柄可跳过此节,因其默认已拥有相应权限。

若使用CreateProcess()的句柄可跳过此节,因其默认已拥有相应权限。

以下为OpenProcessToken()更改句柄权限的方式。

HANDLE hToken;
BOOL bResult = OpenProcessToken(原始句柄, PROCESS_SET_INFORMATION, &hToken);

若未拥有进程句柄,仅已知进程名称,则可通过拍摄进程快照+遍历比对szExeFile获得进程PID后OpenProcess()直接获得,可参考C++代码如下:

#include <Tlhelp32.h>

/* Unicode版本 */
DWORD GetProcessIdByNameW(LPCWSTR lpFileName) {
    // 拍摄进程快照
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnapshot == INVALID_HANDLE_VALUE) {
        return -1;
    }

    PROCESSENTRY32 pe32 = { sizeof(pe32) };
    BOOL bRet = Process32First(hSnapshot, &pe32);

    while (bRet) {
        std::wstring wsExeName = pe32.szExeFile;

        // find找不到值 返回string::npos
        if (wsExeName.find(lpFileName) != wsExeName.npos) {
            CloseHandle(hSnapshot);
            return pe32.th32ProcessID;
        }
        bRet = Process32Next(hSnapshot, &pe32);
    }

    CloseHandle(hSnapshot);
    return -1;
}

/* ANSI多字符集版本 */
DWORD GetProcessIdByNameA(LPCSTR lpFileName) {
    // 拍摄进程快照
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if (hSnapshot == INVALID_HANDLE_VALUE) {
        return -1;
    }

    PROCESSENTRY32 pe32 = { sizeof(pe32) };
    BOOL bRet = Process32First(hSnapshot, &pe32);

    while (bRet) {
        if (0 == strcmp(lpFileName, pe32.szExeFile)) {
            CloseHandle(hSnapshot);
            return pe32.th32ProcessID;
        }
        bRet = Process32Next(hSnapshot, &pe32);
    }
    CloseHandle(hSnapshot);
    return -1;
}

调用:

HANDLE hProcess = OpenProcess(PROCESS_SET_INFORMATION, FALSE, GetProcessIdByName("进程名.exe"));

使用示例

PROCESS_POWER_THROTTLING_STATE 结构指定电源管理相关限制策略,此结构配合 SetProcessInformation() 函数对目标进程使用。

其中ControlMask成员不作为权重开关,EcoQos具体是否生效由StateMask决定。

【C++】

#include <Windows.h>

BOOL SetProcessEcoQoS(HANDLE hProcess, bool bFlag) {
    // 此句柄必须具有 PROCESS_SET_INFORMATION 访问权限
    PROCESS_POWER_THROTTLING_STATE PowerThrottling;
    RtlZeroMemory(&PowerThrottling, sizeof(PowerThrottling));
    PowerThrottling.Version = PROCESS_POWER_THROTTLING_CURRENT_VERSION;

    PowerThrottling.ControlMask = bFlag ? PROCESS_POWER_THROTTLING_EXECUTION_SPEED : NULL;
    PowerThrottling.StateMask = bFlag ? PROCESS_POWER_THROTTLING_EXECUTION_SPEED : NULL;

    if (!SetProcessInformation(hProcess, ProcessPowerThrottling, &PowerThrottling, sizeof(PowerThrottling))) {
        return FALSE;
    }

    if (!SetPriorityClass(hProcess, bFlag ? IDLE_PRIORITY_CLASS : NORMAL_PRIORITY_CLASS)) {
        return FALSE;
    }
    return TRUE;
}

 【C#】

        // 声明导入函数
        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern bool SetProcessInformation([In] IntPtr hProcess,
[In] PROCESS_INFORMATION_CLASS ProcessInformationClass, IntPtr ProcessInformation, uint ProcessInformationSize);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern bool SetPriorityClass(IntPtr handle, uint priorityClass);

        [DllImport("kernel32.dll", SetLastError = true)]
        public static extern IntPtr OpenProcess(uint processAccess, bool bInheritHandle, uint processId);

        private enum PROCESS_INFORMATION_CLASS {
            ProcessMemoryPriority,
            ProcessMemoryExhaustionInfo,
            ProcessAppMemoryInfo,
            ProcessInPrivateInfo,
            ProcessPowerThrottling,
            ProcessReservedValue1,
            ProcessTelemetryCoverageInfo,
            ProcessProtectionLevelInfo,
            ProcessLeapSecondInfo,
            ProcessInformationClassMax,
        }

        //实现
        public static bool SetProcessEcoQoS(IntPtr hProcess, bool bFlag) {
            // 此结构有三个字段Version,ControlMask 和 StateMask
            uint controlMask = 0x1; //非权重开关
            uint stateMask = (uint)(bFlag ? 0x1 : 0x0);
            uint version = 1;
            int szControlBlock = 12; // 三个uint的大小
            IntPtr homo = Marshal.AllocHGlobal(szControlBlock);

            // Marshal.WriteInt32 将一个32位整数写入一个指定偏移量的非托管内存指针
            Marshal.WriteInt32(homo, (int)version); //homo 指向内存块开头
            Marshal.WriteInt32(homo + 4, (int)controlMask); // 将 controlMask 值写入第2字段地址,需将 homo 指针加4字节
            Marshal.WriteInt32(homo + 8, (int)stateMask); // 将 stateMask 值写入第3个字段地址,需将 homo 指针加8个字节
            bool bRet = false;

            // 此句柄必须具有 PROCESS_SET_INFORMATION 访问权限
            if(!SetProcessInformation(hProcess, PROCESS_INFORMATION_CLASS.ProcessPowerThrottling, homo, (uint)szControlBlock)) {
                goto End;
            }
            if(!SetPriorityClass(hProcess, (uint)(bFlag ? 0x40 : 0x20))) {
                goto End;
            }
            bRet = true;
            goto End;
        End:
            Marshal.FreeHGlobal(homo); 
            return bRet;
        }

在C#版本中可以自建PROCESS_POWER_THROTTLING_STATE,但由于防止代码冗余,此处直接使用了Marshal.WriteInt32()函数进行了指针偏移内存写入,以完成对其(在示例中为homo指针)封装。

写在最后,本文作为新人首发尝试,可能有很多不足,还请多多包涵,祝大家编码愉快!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值