【问题标题】:How to get the CPU Usage in C#?如何在 C# 中获取 CPU 使用率?
【发布时间】:2010-09-21 15:22:50
【问题描述】:

我想在 C# 中获取应用程序的总体总 CPU 使用率。我找到了很多方法来挖掘进程的属性,但我只想要进程的 CPU 使用率,以及你在 TaskManager 中获得的总 CPU。

我该怎么做?

【问题讨论】:

标签: c# cpu-usage


【解决方案1】:

您可以使用System.Diagnostics 中的PerformanceCounter 类。

像这样初始化:

PerformanceCounter cpuCounter;
PerformanceCounter ramCounter;

cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total");
ramCounter = new PerformanceCounter("Memory", "Available MBytes");

这样吃:

public string getCurrentCpuUsage(){
            return cpuCounter.NextValue()+"%";
}

public string getAvailableRAM(){
            return ramCounter.NextValue()+"MB";
} 

【讨论】:

  • 很好 - 但原始来源似乎来自这里:zamov.online.fr/EXHTML/CSharp/CSharp_927308.html
  • 根据我的发现,我必须使用 cpuCounter.NextValue() 两次,并且在它们之间我不得不 Sleep(500)
  • 马特是对的。甚至包括错误,比如忘记“return”关键字。
  • 是的,它看起来像是该链接的副本,因此作为原始链接的参考链接会很不错。另一方面,CMS 也很高兴在这里提供答案,因此懒惰的开发人员不必在 Google 上搜索相同的答案。 :o)
  • 您需要调用 .NextValue 两次,中间调用 System.Threading.Thread.Sleep (1000 毫秒就足够了)。请参阅blogs.msdn.com/b/bclteam/archive/2006/06/02/618156.aspx 了解有关为什么需要这样做的更多信息,但高级摘要是您需要两个样本才能计算值,并且您需要给操作系统时间来获取这两个样本。
【解决方案2】:

CMS 是正确的,但如果您在 Visual Studio 中使用服务器资源管理器并使用性能计数器选项卡,那么您可以弄清楚如何获得大量有用的指标。​​

【讨论】:

    【解决方案3】:

    您可以使用 WMI 获取 CPU 百分比信息。如果您拥有正确的权限,您甚至可以登录到远程计算机。查看http://www.csharphelp.com/archives2/archive334.html 了解您可以完成的工作。

    Win32_Process 命名空间的 MSDN 参考可能也很有帮助。

    另见 CodeProject 示例How To: (Almost) Everything In WMI via C#

    【讨论】:

      【解决方案4】:

      没关系,我明白了!感谢您的帮助!

      这是执行此操作的代码:

      private void button1_Click(object sender, EventArgs e)
      {
          selectedServer = "JS000943";
          listBox1.Items.Add(GetProcessorIdleTime(selectedServer).ToString());
      }
      
      private static int GetProcessorIdleTime(string selectedServer)
      {
          try
          {
              var searcher = new
                 ManagementObjectSearcher
                   (@"\\"+ selectedServer +@"\root\CIMV2",
                    "SELECT * FROM Win32_PerfFormattedData_PerfOS_Processor WHERE Name=\"_Total\"");
      
              ManagementObjectCollection collection = searcher.Get();
              ManagementObject queryObj = collection.Cast<ManagementObject>().First();
      
              return Convert.ToInt32(queryObj["PercentIdleTime"]);
          }
          catch (ManagementException e)
          {
              MessageBox.Show("An error occurred while querying for WMI data: " + e.Message);
          }
          return -1;
      }
      

      【讨论】:

      • 添加获取服务器名称而不是变量 selectedServer 更好。 like this.string computername = Environment.GetEnvironmentVariable("computername");
      【解决方案5】:

      比要求的多一点,但我使用额外的计时器代码来跟踪并提醒 CPU 使用率是否持续 1 分钟或更长时间达到 90% 或更高。

      public class Form1
      {
      
          int totalHits = 0;
      
          public object getCPUCounter()
          {
      
              PerformanceCounter cpuCounter = new PerformanceCounter();
              cpuCounter.CategoryName = "Processor";
              cpuCounter.CounterName = "% Processor Time";
              cpuCounter.InstanceName = "_Total";
      
                           // will always start at 0
              dynamic firstValue = cpuCounter.NextValue();
              System.Threading.Thread.Sleep(1000);
                          // now matches task manager reading
              dynamic secondValue = cpuCounter.NextValue();
      
              return secondValue;
      
          }
      
      
          private void Timer1_Tick(Object sender, EventArgs e)
          {
              int cpuPercent = (int)getCPUCounter();
              if (cpuPercent >= 90)
              {
                  totalHits = totalHits + 1;
                  if (totalHits == 60)
                  {
                      Interaction.MsgBox("ALERT 90% usage for 1 minute");
                      totalHits = 0;
                  }                        
              }
              else
              {
                  totalHits = 0;
              }
              Label1.Text = cpuPercent + " % CPU";
              //Label2.Text = getRAMCounter() + " RAM Free";
              Label3.Text = totalHits + " seconds over 20% usage";
          }
      }
      

      【讨论】:

      • getRAMCounter() 在哪里?
      • cpuCounter.NextValue returns a float。那么为什么要将它分配给dynamic?那么为什么将dynamic 作为object 返回呢?那么为什么要尝试在int cpuPercent = getCPUCounter() 行中将object 分配给int? (该代码不会编译。)
      • 我得到“找不到类型或命名空间名称 PerformanceCounter”,并且在 System.Threading 命名空间中也找不到线程。
      • 保证每个人都会得到“我得到”找不到类型或命名空间名称PerformanceCounter”错误。解决方案不起作用。
      【解决方案6】:

      这个类每 1 秒自动轮询一次计数器,也是线程安全的:

      public class ProcessorUsage
      {
          const float sampleFrequencyMillis = 1000;
      
          protected object syncLock = new object();
          protected PerformanceCounter counter;
          protected float lastSample;
          protected DateTime lastSampleTime;
      
          /// <summary>
          /// 
          /// </summary>
          public ProcessorUsage()
          {
              this.counter = new PerformanceCounter("Processor", "% Processor Time", "_Total", true);
          }
      
          /// <summary>
          /// 
          /// </summary>
          /// <returns></returns>
          public float GetCurrentValue()
          {
              if ((DateTime.UtcNow - lastSampleTime).TotalMilliseconds > sampleFrequencyMillis)
              {
                  lock (syncLock)
                  {
                      if ((DateTime.UtcNow - lastSampleTime).TotalMilliseconds > sampleFrequencyMillis)
                      {
                          lastSample = counter.NextValue();
                          lastSampleTime = DateTime.UtcNow;
                      }
                  }
              }
      
              return lastSample;
          }
      }
      

      【讨论】:

      • System.DateTime 实际上是一个 8 字节值类型,这意味着对 DateTime 变量的赋值不是原子的。此代码在 32 位平台上不是线程安全的。
      【解决方案7】:

      在花了一些时间阅读了几个看起来相当复杂的不同线程之后,我想出了这个。我需要一台 8 核机器来监控 SQL 服务器。对于下面的代码,我将“sqlservr”作为 appName 传入。

      private static void RunTest(string appName)
      {
          bool done = false;
          PerformanceCounter total_cpu = new PerformanceCounter("Process", "% Processor Time", "_Total");
          PerformanceCounter process_cpu = new PerformanceCounter("Process", "% Processor Time", appName);
          while (!done)
          {
              float t = total_cpu.NextValue();
              float p = process_cpu.NextValue();
              Console.WriteLine(String.Format("_Total = {0}  App = {1} {2}%\n", t, p, p / t * 100));
              System.Threading.Thread.Sleep(1000);
          }
      }
      

      它似乎正确地测量了我的 8 核服务器上 SQL 使用的 CPU 百分比。

      【讨论】:

      • total_cpu 应该是 PerformanceCounter("Processor"),而不是 PerformanceCounter("Process").. 否则你只会得到 100% * 核心数。
      • 您在哪里将done 设置为true?除非我忽略了什么,否则这似乎是一个无限循环:while(!done){...}
      • @Manfred 确实是死循环
      • 老话题,只是评论 |你为什么不使用 while(true) ?
      • 我得到“找不到类型或命名空间名称 PerformanceCounter
      【解决方案8】:

      我不喜欢在所有 PerformanceCounter 解决方案中添加 1 秒的停顿时间。相反,我选择使用WMI 解决方案。存在 1 秒等待/停止的原因是为了在使用 PerformanceCounter 时使读数准确。但是,如果您经常调用此方法并刷新此信息,我建议不要经常产生这种延迟......即使考虑执行异步进程来获取它。

      我从这里Returning CPU usage in WMI using C# 开始使用 sn-p,并在下面的博客文章中添加了对该解决方案的完整说明:

      Get CPU Usage Across All Cores In C# Using WMI

      【讨论】:

      • 请在此处包含答案,而不是链接到您的博客。
      • @Herman - 我不只是链接到我的博客;我首先给出了解释,然后在此处提供了一个链接,以获得更深入的答案。
      • 您博文中的解决方案就像 12 行代码。除了试图让人们访问您的博客之外,为什么不在您的答案中包含这一点?
      • 链接可能会被破坏,并且当核心内容内联时扫描答案会容易得多。对不起,我的其他回复很严厉,我不是来给你难的。 :)
      • 我也建议在这里复制代码,因为它很短。除此之外,您的页面上还有一个错误: Cast 中的 ManagementObject 需要大写,类型区分大小写,并且您的带有 Cast 的代码无法编译。
      【解决方案9】:

      这似乎对我有用,一个等待处理器达到一定百分比的例子

      var cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total");
      int usage = (int) cpuCounter.NextValue();
      while (usage == 0 || usage > 80)
      {
           Thread.Sleep(250);
           usage = (int)cpuCounter.NextValue();
      }
      

      【讨论】:

      • 使用量为0时为什么还在睡觉?
      • 我得到“找不到类型或命名空间名称 PerformanceCounter
      【解决方案10】:
      public int GetCpuUsage()
      {
          var cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total", Environment.MachineName);
          cpuCounter.NextValue();
          System.Threading.Thread.Sleep(1000); //This avoid that answer always 0
          return (int)cpuCounter.NextValue();
      }
      

      此链接中的原始信息https://gavindraper.com/2011/03/01/retrieving-accurate-cpu-usage-in-c/

      【讨论】:

      • 我得到“找不到类型或命名空间名称 PerformanceCounter”
      • @NeoTechni - 还没有人提到它,但您需要包含 System.Diagnostics.PerformanceCounter NuGet,并添加“使用 System.Diagnostics;”到你的代码。
      猜你喜欢
      • 1970-01-01
      • 2011-10-18
      • 2011-03-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多