这个问题“如何在 C# 中获取 CPU 使用率?” 显示了在 .NET 中获取计算机当前 CPU 使用率 (%) 的一些方法。
由于 CPU 使用率波动非常频繁,我认为当前的 CPU 使用率通常不能很好地指示计算机的繁忙程度(例如,用于调度或负载平衡目的)。有没有一种有效的方法来获得最后 x 分钟的平均 CPU 使用率,例如最后 5 分钟?
我正在考虑类似方法 GetAverageCpuUsage(int period) 可以由负载平衡或调度模块调用的方法。
这个问题“如何在 C# 中获取 CPU 使用率?” 显示了在 .NET 中获取计算机当前 CPU 使用率 (%) 的一些方法。
由于 CPU 使用率波动非常频繁,我认为当前的 CPU 使用率通常不能很好地指示计算机的繁忙程度(例如,用于调度或负载平衡目的)。有没有一种有效的方法来获得最后 x 分钟的平均 CPU 使用率,例如最后 5 分钟?
我正在考虑类似方法 GetAverageCpuUsage(int period) 可以由负载平衡或调度模块调用的方法。
实际上,这正是另一个问题中第二个最受好评的答案中的PerformanceCounter所做的,它们的测量时间仅超过 1 秒。
NextValue()
它给你的百分比是最后一次在柜台上进行的 CPU seance 的平均百分比。因此,如果您想要过去 5 分钟的平均 cpu,只需NextValue()
每 5 分钟调用一次。
这是一篇很好的文章,解释了如何使用性能计数器。
上面的答案为计算 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;
}
注意 lowDateTime 的 UINT32。这是因为,至少在 C# 中,comtype.FILETIME 结构将 DWORD 强制转换为 int32,因此如果该值大于 MAX 有符号 Int,您会看到一个负值,这种情况绝不应该出现。如果您将其直接转换为“UINT64”类型,则在内部为保留符号,它首先转换为 Int64,然后转换为 UInt64,因此您会看到不正确的值。相反,您希望将 lowDateTime 转换为 Uint32 类型以消除负号,然后转换为 UInt64(这将自动发生,因为它是 | 操作的一部分)。dwHighDateTime 组件也应该如此,但这很好,因为它通常不应该超过 MaxInt (嗯,这又取决于你的用例)。
尝试类似:
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();
在某事上有所帮助