You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过PID计算每个进程的CPU占用百分比?附现有实现代码

公式正确性验证

你给出的公式是错误的,逻辑混淆了系统空闲时间和进程时间的统计维度,计算结果会是整机CPU占用率而非单个进程的CPU占用率。
正确的单进程CPU占用率计算逻辑如下:

单进程CPU占用率 = (统计间隔内进程内核时间增量 + 进程用户时间增量) / (统计间隔内系统总时间增量) * 100%
系统总时间增量 = 统计间隔时长 * 逻辑CPU核心数 * 单位时间时钟滴答数,也可以通过(系统内核时间增量 + 系统用户时间增量)直接计算得到

现有代码问题梳理
  • 全局静态变量存储上一次时间,遍历多进程时会互相覆盖,每个进程需要独立存储自己的上一次内核、用户时间戳
  • OpenProcess申请PROCESS_ALL_ACCESS权限过高,大部分系统进程、权限更高的进程会拒绝访问,仅需要申请PROCESS_QUERY_LIMITED_INFORMATION权限即可满足读取进程时间的需求,大幅降低打开失败概率
  • 遍历每个进程时单独Sleep 2.5秒的逻辑完全不可用,若系统中存在上百个进程,单次遍历耗时会达到数百秒,正确逻辑是批量采集所有进程的第一次时间,统一等待间隔后批量采集第二次时间统一计算
  • 函数入参逻辑不匹配,你定义的CalculateCPULoad仅接收两个参数,调用时却传入了三个参数,逻辑完全不对应
修正后代码示例
#include <windows.h>
#include <tlhelp32.h>
#include <map>
#include <iostream>
#include <tchar.h>

// FILETIME转64位整数
static ULONGLONG FileTimeToInt64(const FILETIME& ft) { 
    return (((ULONGLONG)(ft.dwHighDateTime)) << 32) | ((ULONGLONG)ft.dwLowDateTime); 
}

// 获取系统逻辑核心数
int GetLogicalCpuCount() {
    SYSTEM_INFO sysInfo = {0};
    GetSystemInfo(&sysInfo);
    return sysInfo.dwNumberOfProcessors;
}

int main() {
    const int CALC_INTERVAL = 1000; // 统计间隔1秒,可自行调整
    int cpuCount = GetLogicalCpuCount();
    std::map<DWORD, std::pair<ULONGLONG, ULONGLONG>> lastProcessTime; // 存储每个PID的上一次内核、用户时间
    ULONGLONG lastSysKernel = 0, lastSysUser = 0;

    while (true) { // 循环刷新,若不需要持续刷新可去掉外层循环
        // 第一次采集:获取当前系统时间
        FILETIME sysIdle, sysKernel, sysUser;
        GetSystemTimes(&sysIdle, &sysKernel, &sysUser);
        ULONGLONG curSysKernel = FileTimeToInt64(sysKernel);
        ULONGLONG curSysUser = FileTimeToInt64(sysUser);
        ULONGLONG sysDelta = (curSysKernel + curSysUser) - (lastSysKernel + lastSysUser);

        // 采集所有进程的当前时间
        HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
        if (hSnap == INVALID_HANDLE_VALUE) break;

        PROCESSENTRY32 pe = {0};
        pe.dwSize = sizeof(PROCESSENTRY32);
        if (Process32First(hSnap, &pe)) {
            do {
                HANDLE hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pe.th32ProcessID);
                if (hProcess) {
                    FILETIME ftCreate, ftExit, ftKernel, ftUser;
                    if (GetProcessTimes(hProcess, &ftCreate, &ftExit, &ftKernel, &ftUser)) {
                        ULONGLONG curKernel = FileTimeToInt64(ftKernel);
                        ULONGLONG curUser = FileTimeToInt64(ftUser);

                        // 不是第一次采集则计算占用率
                        if (lastSysKernel != 0 && lastProcessTime.count(pe.th32ProcessID)) {
                            auto& lastTime = lastProcessTime[pe.th32ProcessID];
                            ULONGLONG procDelta = (curKernel - lastTime.first) + (curUser - lastTime.second);
                            float cpuUsage = 0.0f;
                            if (sysDelta > 0) {
                                cpuUsage = (procDelta * 100.0f) / sysDelta;
                                // 如果要显示和任务管理器一致的单核心占比,不需要除以cpuCount
                                // 如果要显示占整机的比例,加上:cpuUsage /= cpuCount;
                            }
                            _tprintf(TEXT("进程名:%s \t PID:%u \t CPU占用:%.2f%%\n"), pe.szExeFile, pe.th32ProcessID, cpuUsage);
                        }
                        // 更新存储的进程时间
                        lastProcessTime[pe.th32ProcessID] = {curKernel, curUser};
                    }
                    CloseHandle(hProcess);
                }
            } while (Process32Next(hSnap, &pe));
        }
        CloseHandle(hSnap);

        // 更新系统时间
        lastSysKernel = curSysKernel;
        lastSysUser = curSysUser;

        // 等待间隔,GUI程序可替换为定时器避免阻塞
        Sleep(CALC_INTERVAL);
        system("cls"); // 清屏刷新,可根据需求调整
    }
    return 0;
}
Sleep优化方案
  • 若为GUI程序,可将进程统计逻辑放到独立工作线程,用SetTimer触发定时采集,避免阻塞主线程导致界面卡顿
  • 不需要高精度统计的场景下,1-2秒的间隔已经足够贴合系统任务管理器的显示效果,不需要过短的间隔增加系统负载

内容的提问来源于stack exchange,提问作者PraysforWind

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 00:27:00