我有一个 Windows 应用程序,应该每 40 毫秒精确执行一次操作(实际上它可以配置为任何内容,但 40 毫秒是典型设置)。它有足够的时间来完成任务,因此大部分时间片都处于空闲状态,但它需要以精确的时间间隔进行报告。我们不断监控,看看实际报告的时间是否多于或少于 40 毫秒。
在Windows 7、8或10下,表现良好。在Windows 11下,我们遇到了一个新问题:应用程序只有在其窗口不隐藏的情况下才能正常运行。如果它的窗口隐藏在另一个应用程序(Firefox、记事本等)的“最大化”窗口后面,那么 5 秒后计时就会变得锯齿状 - 超过 40 毫秒的截止时间,然后低于补偿,然后再次超过,等等。如果您按 alt-tab 返回到我们的应用程序窗口,则必须再等待 5 秒钟,但随后时间又恢复正常。 仅当应用程序位于最大化窗口后面时才会发生这种情况:如果应用程序的窗口隐藏在
非最大化记事本窗口后面,并且只有一点点裸露桌面显示在某处,那么计时始终保持平稳。 看起来,Windows 11 的窗口管理器正在根据记事本或其他内容的最大化做出决定,将我们的应用程序置于某种“后台”模式。这是什么模式?我的应用程序是否可以进行一些 Windows API 调用,以防止自身进入此模式?
我们找到了一种让它变得更糟糕的方法:如果我们使用
SetCurrentProcessExplicitAppUserModelID()
注册进程,那么我们会得到不同的行为:具体来说,我们获得了 10 秒的良好性能,然后它就会变坏并且一直变坏。不管我们是在前台还是后台。这可能是一个线索,但我不确定它指向哪个方向,以解决最初的问题。 如果相关:我们的应用程序是用 C++ 编写的,使用 MSVC 编译,并使用 Qt 6 作为其窗口。
这种现象似乎被称为“过程功率节流”。
Microsoft当进程选择启用
PROCESS_POWER_THROTTLING_EXECUTION_SPEED
时,该进程将被归类为 EcoQoS。系统将尝试通过降低 CPU 频率或使用更节能的内核等策略来提高电源效率。当工作对前台用户体验没有贡献时,应使用 EcoQoS,这样可以延长电池寿命,并减少热量和风扇噪音。 EcoQoS 不应用于性能关键或前台用户体验。 (在 Windows 11 之前,EcoQoS 级别不存在,进程被标记为 LowQoS)。如果应用程序未显式启用PROCESS_POWER_THROTTLING_EXECUTION_SPEED
,系统将使用自己的启发式方法自动推断服务质量级别。有关更多信息,请参阅服务质量。
当进程选择启用时,该进程发出的任何当前计时器解析请求都将被忽略。属于该进程的计时器不再保证以更高的计时器分辨率到期,这可以提高电源效率。显式禁用PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION
PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION
后,系统会记住并尊重进程之前的任何计时器解析请求。默认情况下,在 Windows 11 中,如果窗口拥有进程完全被遮挡、最小化或最终用户不可见且听不到声音,Windows 可能会自动忽略计时器分辨率请求,因此不保证比默认分辨率更高的分辨率系统分辨率。
我们实际上可以通过解决第二点来确定我们的时间安排:#ifndef PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION # define PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION 0x4 // defined in Windows 11 headers but not in earlier versions #endif PROCESS_POWER_THROTTLING_STATE state = { 0 }; state.Version = PROCESS_POWER_THROTTLING_CURRENT_VERSION; state.ControlMask = PROCESS_POWER_THROTTLING_IGNORE_TIMER_RESOLUTION; state.StateMask = 0; SetProcessInformation(GetCurrentProcess(), ProcessPowerThrottling, &state, sizeof(state)); // (call fails in Windows 10, so just ignore the result)