NextValue() return's 0

2019-09-05 02:57发布

问题:

I am trying to get the NextValue of a PerformanceCounter class using PhysicalDisk. Some reason that I can't seem to find out why, it return's 0 every time.

  PerformanceCounter pcDiskTime = new PerformanceCounter("PhysicalDisk", "% Disk Time", "_Total");
  Single sinDisk = pcDiskTime.NextValue(); //returns 0.0

Using the above and calling pcDiskTime.NextValue return's 0. I have other counter's that are working just fine and return what I need.

.RawValue does return something, but is not the value I would need. Is there something obvious that I am not doing?

Note: I have verified through Performance Monitor these are indeed the correct category, counter name and instance name. I have also tried to call .NextValue() twice as sometimes the first return's 0.0, but this does not help.

回答1:

First time it will return zero because there is no previous value to compare, do as below.

PerformanceCounter pcDiskTime = new PerformanceCounter("PhysicalDisk", "% Disk Time", "_Total");
//first time call 
float perfCounterValue = pcDiskTime.NextValue();
//wait some time
System.Threading.Thread.Sleep(1000);
//get the value again
perfCounterValue = pcDiskTime.NextValue();

If the calculated value of a counter depends on two counter reads, the first read operation returns 0.0. Resetting the performance counter properties to specify a different counter is equivalent to creating a new performance counter, and the first read operation using the new properties returns 0.0. The recommended delay time between calls to the NextValue method is one second, to allow the counter to perform the next incremental read.



回答2:

This problem annoyed me as well. There were a couple problems that seemed like there should be an easy package to solve but I didn't see one. The first is of course that a value of 0 on the first request is useless. Since you already know that the first response is 0, why doesn't the function just take that into account and return the true .NextValue()?

The second problem is that an instantaneous reading may be wildly inacurrate when trying to make decisions on what resources your app may have available to it since it could be spiking, or between spikes.

My solution was to do a for loop that cycles through and gives you an average for the past few seconds. you can adjust the counter to make it shorter or longer (as long as it is more than 2).

public static float ProcessorUtilization;

public static float GetAverageCPU()
{
    PerformanceCounter cpuCounter = new PerformanceCounter("Process", "% Processor Time", Process.GetCurrentProcess().ProcessName);
    for (int i = 0; i < 11; ++i)
    {
        ProcessorUtilization += (cpuCounter.NextValue() / Environment.ProcessorCount);
    }
    // Remember the first value is 0, so we don't want to average that in.
    Console.Writeline(ProcessorUtilization / 10); 
    return ProcessorUtilization / 10;
}