【问题标题】:Get average CPU usage of a computer in last x minute获取计算机在过去 x 分钟内的平均 CPU 使用率
【发布时间】:2013-02-05 05:54:02
【问题描述】:

这个问题"How to get the CPU Usage in C#?" 展示了一些在 .NET 中获取计算机当前 CPU 使用率 (%) 的方法。

由于 CPU 使用率波动非常频繁,我认为当前的 CPU 使用率通常不能很好地指示计算机的繁忙程度(例如,用于调度或负载平衡目的)。有没有一种有效的方法来获得最后 x 分钟的平均 CPU 使用率,例如最后5分钟?

我正在考虑类似 GetAverageCpuUsage(int period) 的方法,可以由负载平衡或调度模块调用。

【问题讨论】:

    标签: c# .net cpu-usage system.diagnostics


    【解决方案1】:

    实际上,这正是另一个问题中 the 2nd most upvoted answer 中的 PerformanceCounter 所做的,它们的测量时间仅超过 1 秒。

    它给你的百分比是最后一次NextValue() 在柜台上进行的平均 CPU 百分比。因此,如果您想要过去 5 分钟的平均 CPU,只需每 5 分钟调用一次 NextValue()

    Here is a good article 解释如何使用性能计数器。

    【讨论】:

    • 在这种方法中,您必须知道何时第一次调用 NextValue()。就我而言,这就是问题所在,因为我希望 GetAverageCpuUsage 按需可用并且可以随时调用。
    • 问题是它没有为你保留历史记录。您可以定期使用NextSample 而不是 NextValue,然后自己进行数学运算(end value - start value)/(end time - start time),您的程序负责存储这些值,以便其他用户可以查询它,它可以在它的数据库中查找并计算一个值..
    • 另一个选项是 set up a counter in windows 滚动日志文件,您可以查询该文件以获取最后 5 分钟的数据。
    • @NextSample 和 NextValue 有什么区别?顺便说一句,谢谢你的回答,+1
    • NextSample 将原始数据作为结构提供给您。然后,您可以使用该结构的属性(样本的时间戳和与计数器关联的数值),然后执行我在第一条评论中提到的“开始 - 结束”值方法。
    【解决方案2】:

    上面的答案为计算 CPU 使用率的方法提供了一个很好的例子。但我想指出一些不正确且被误导的东西。 SubtractTimes 函数需要稍有不同。

    private UInt64 SubtractTimes(ComTypes.FILETIME a, ComTypes.FILETIME b)
        {
            UInt64 aInt = ((UInt64)(a.dwHighDateTime << 32)) | (UInt32)a.dwLowDateTime;
            UInt64 bInt = ((UInt64)(b.dwHighDateTime << 32)) | (UInt32)b.dwLowDateTime;
    
            return aInt - bInt;
        }
    

    注意低日期时间的 UINT32。这是因为,至少在 C# 中,comtype.FILETIME 结构将 DWORD 强制转换为 int32,因此如果该值大于 MAX 有符号 Int,您会看到一个负值,这种情况绝不应该出现。如果您将其直接转换为“UINT64”类型,则在内部为保留符号,它首先转换为 Int64,然后转换为 UInt64,因此您会看到不正确的值。相反,您希望将 lowDateTime 转换为 Uint32 类型以消除负号,然后转换为 UInt64(这将自动发生,因为它是 | 操作的一部分)。 dwHighDateTime 组件也应该如此,但这很好,因为它通常不应该超过 MaxInt(嗯,这又取决于你的用例)。

    【讨论】:

      【解决方案3】:

      尝试类似:

      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Text;
      using System.Runtime.InteropServices;
      using ComTypes = System.Runtime.InteropServices.ComTypes;
      using System.Threading;
      using System.Diagnostics;
      
      namespace example1
      {
          public class CpuUsage
          {
              [DllImport("kernel32.dll", SetLastError = true)]
              static extern bool GetSystemTimes(
                          out ComTypes.FILETIME lpIdleTime,
                          out ComTypes.FILETIME lpKernelTime,
                          out ComTypes.FILETIME lpUserTime
                          );
      
              ComTypes.FILETIME _prevSysKernel;
              ComTypes.FILETIME _prevSysUser;
      
              TimeSpan _prevProcTotal;
      
              Int16 _cpuUsage;
              DateTime _lastRun;
              long _runCount;
      
              public CpuUsage()
              {
                  _cpuUsage = -1;
                  _lastRun = DateTime.MinValue;
                  _prevSysUser.dwHighDateTime = _prevSysUser.dwLowDateTime = 0;
                  _prevSysKernel.dwHighDateTime = _prevSysKernel.dwLowDateTime = 0;
                  _prevProcTotal = TimeSpan.MinValue;
                  _runCount = 0;
              }
      
              public short GetUsage()
              {
                  short cpuCopy = _cpuUsage;
                  if (Interlocked.Increment(ref _runCount) == 1)
                  {
                      if (!EnoughTimePassed)
                      {
                          Interlocked.Decrement(ref _runCount);
                          return cpuCopy;
                      }
      
                      ComTypes.FILETIME sysIdle, sysKernel, sysUser;
                      TimeSpan procTime;
      
                      Process process = Process.GetCurrentProcess();
                      procTime = process.TotalProcessorTime;
      
                      if (!GetSystemTimes(out sysIdle, out sysKernel, out sysUser))
                      {
                          Interlocked.Decrement(ref _runCount);
                          return cpuCopy;
                      }
      
                      if (!IsFirstRun)
                      {
                          UInt64 sysKernelDiff = SubtractTimes(sysKernel, _prevSysKernel);
                          UInt64 sysUserDiff = SubtractTimes(sysUser, _prevSysUser);
      
                          UInt64 sysTotal = sysKernelDiff + sysUserDiff;
      
                          Int64 procTotal = procTime.Ticks - _prevProcTotal.Ticks;
      
                          if (sysTotal > 0)
                          {
                              _cpuUsage = (short)((100.0 * procTotal) / sysTotal);
                          }
                      }
      
                      _prevProcTotal = procTime;
                      _prevSysKernel = sysKernel;
                      _prevSysUser = sysUser;
      
                      _lastRun = DateTime.Now;
      
                      cpuCopy = _cpuUsage;
                  }
                  Interlocked.Decrement(ref _runCount);
      
                  return cpuCopy;
      
              }
      
              private UInt64 SubtractTimes(ComTypes.FILETIME a, ComTypes.FILETIME b)
              {
                  UInt64 aInt = ((UInt64)(a.dwHighDateTime << 32)) | (UInt64)a.dwLowDateTime;
                  UInt64 bInt = ((UInt64)(b.dwHighDateTime << 32)) | (UInt64)b.dwLowDateTime;
      
                  return aInt - bInt;
              }
      
              private bool EnoughTimePassed
              {
                  get
                  {
                      const int minimumElapsedMS = 250;
                      TimeSpan sinceLast = DateTime.Now - _lastRun;
                      return sinceLast.TotalMilliseconds > minimumElapsedMS;
                  }
              }
      
              private bool IsFirstRun
              {
                  get
                  {
                      return (_lastRun == DateTime.MinValue);
                  }
              }
          }
      }
      

      在你的代码中使用它之后:

         CpuUsage _cu = new CpuUsage();
         string cpuUsage = _cu.GetUsage();
      

      帮助过某事

      【讨论】:

      • 我不明白为什么 Process process = Process.GetCurrentProcess(); procTime = process.TotalProcessorTime;涉及到这里。另一个示例不使用 this 而是: var thisTotal = thisKernel + thisUser; var totalSinceLast = thisTotal - pPrevTotal; var idleSinceLast = thisIdle - pPrevIdle;双倍净空 = (double)idleSinceLast / (double)totalSinceLast;双负载 = 1.0 - 净空;我想你的例子是计算当前进程而不是系统的 cpu 使用率?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-10-05
      • 1970-01-01
      • 2020-04-25
      • 2019-12-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多