获取 CPU 和 RAM 使用情况

Get CPU and RAM usage

我需要在进程执行期间获取 ram 内存和 CPU 使用情况(进程有时 运行 超过 30 分钟)。我能够获得免费 RAM,但与任务管理器的值相比,CPU 用法不正确。难道我做错了什么?这是我的代码:

class Program
{
    static List<float> AvailableCPU = new List<float>();
    static List<float> AvailableRAM = new List<float>();

    protected static PerformanceCounter cpuCounter;
    protected static PerformanceCounter ramCounter;
    static void Main(string[] args)
    {
        cpuCounter = new PerformanceCounter();
        cpuCounter.CategoryName = "Processor";
        cpuCounter.CounterName = "% Processor Time";
        cpuCounter.InstanceName = "_Total";

        ramCounter = new PerformanceCounter("Memory", "Available MBytes");

        try
        {
            System.Timers.Timer t = new System.Timers.Timer(1200);
            t.Elapsed += new ElapsedEventHandler(TimerElapsed);
            t.Start();
            Thread.Sleep(10000);
        }
        catch (Exception e)
        {
            Console.WriteLine("catched exception");
        }
        Console.ReadLine();

    }

    public static void TimerElapsed(object source, ElapsedEventArgs e)
    {
        float cpu = cpuCounter.NextValue();
        float ram = ramCounter.NextValue();
        Console.WriteLine(string.Format("CPU Value: {0}, ram value: {1}", cpu, ram));
        AvailableCPU.Add(cpu);
        AvailableRAM.Add(ram);
    }

}

但是当我 运行 程序时,这是它打印到控制台的内容,与任务管理器中的值相比:

我做错了什么?

这是我发现的:我为每个核心创建了一个包含 PerformanceCounter 个对象的列表,我添加百分比并将结果除以物理核心数:

    class Program
    {
        static List<float> AvailableCPU = new List<float>();
        static List<float> AvailableRAM = new List<float>();

        protected static PerformanceCounter cpuCounter;
        protected static PerformanceCounter ramCounter;
        static List<PerformanceCounter> cpuCounters = new List<PerformanceCounter>();
        static int cores = 0;
        static void Main(string[] args)
        {
            cpuCounter = new PerformanceCounter();
            cpuCounter.CategoryName = "Processor";
            cpuCounter.CounterName = "% Processor Time";
            cpuCounter.InstanceName = "_Total";

            foreach (var item in new System.Management.ManagementObjectSearcher("Select * from Win32_Processor").Get())
            {
                cores = cores + int.Parse(item["NumberOfCores"].ToString());
            }

            ramCounter = new PerformanceCounter("Memory", "Available MBytes");

            int procCount = System.Environment.ProcessorCount;
            for(int i = 0; i < procCount; i++)
            {
                System.Diagnostics.PerformanceCounter pc = new System.Diagnostics.PerformanceCounter("Processor", "% Processor Time", i.ToString());
                cpuCounters.Add(pc);
            }

            Thread c = new Thread(ConsumeCPU);
            c.IsBackground = true;
            c.Start();

            try
            {
                System.Timers.Timer t = new System.Timers.Timer(1200);
                t.Elapsed += new ElapsedEventHandler(TimerElapsed);
                t.Start();
                Thread.Sleep(10000);
            }
            catch (Exception e)
            {
                Console.WriteLine("catched exception");
            }
            Console.ReadLine();

        }

        public static void ConsumeCPU()
        {
            int percentage = 60;
            if (percentage < 0 || percentage > 100)
                throw new ArgumentException("percentage");
            Stopwatch watch = new Stopwatch();
            watch.Start();
            while (true)
            {
                // Make the loop go on for "percentage" milliseconds then sleep the 
                // remaining percentage milliseconds. So 40% utilization means work 40ms and sleep 60ms
                if (watch.ElapsedMilliseconds > percentage)
                {
                    Thread.Sleep(100 - percentage);
                    watch.Reset();
                    watch.Start();
                }
            }
        }

        public static void TimerElapsed(object source, ElapsedEventArgs e)
        {
            float cpu = cpuCounter.NextValue();
            float sum = 0;
            foreach(PerformanceCounter c in cpuCounters)
            {
                sum = sum + c.NextValue();
            }
            sum = sum / (cores);
            float ram = ramCounter.NextValue();
            Console.WriteLine(string.Format("CPU Value 1: {0}, cpu value 2: {1} ,ram value: {2}", sum, cpu, ram));
            AvailableCPU.Add(sum);
            AvailableRAM.Add(ram);
        }

    }

下面是结果截图(如您所见,第一种方法更精确):

你的价值观没有问题。

您看到与任务管理器 returns 不同的原因是 "CPU usage" 值是 给定时间间隔 计算得出的值,即在两个值之间NextValue() 来电。如果您同时执行任务管理器 "doesn't call its own NextValue"(如果我们简化其工作方式),您将不会 return 获得相同的结果。

想象一下以下场景:

Time 0: 0% actual CPU usage
Time 1: 50% actual CPU usage
Time 2: 70% actual CPU usage
Time 3: 2% actual CPU usage
Time 4: 100% actual CPU usage
  • 如果您检查时间 1 和时间 3 之间的值,您将 return 基于“50% 和 2%”的值。
  • 如果任务管理器检查时间 2 和时间 4 之间的值,它将 return 不同的值,即基于“70% 和 100%”的值。

您可以尝试为您自己的应用程序生成多个进程,您应该也会看到不同的结果。