什么是查询过程性能计数器的最高性能的方法?

我试图实现一个性能监视工具,我想监视基本的东西,如内存和CPU。

我试图这样做,通过使用性能计数器,因为我相信这是在C#中查询过程性能的“正确”方式,这是一些示例代码:

class Program { static void Main(string[] args) { while (true) { var pcs = Process.GetProcesses() .Select(p => new PerformanceCounter("Process", "Working Set - Private", p.ProcessName)); var sw = Stopwatch.StartNew(); foreach (var pc in pcs) pc.NextValue(); Console.WriteLine($"Time taken to read {pcs.Count()} performance counters: {sw.ElapsedMilliseconds}ms"); Thread.Sleep(1000); } } } 

在这里输入图像说明

因此,在我的系统上查询进程的时间显而易见〜12.5毫秒,是令人难以接受的缓慢。 应该怎么做?

我已经在这个post中提出了一个相关的问题: 性能计数器读访问速度非常慢 – 任务pipe理器如何做到这一点?

但是我意识到自己在这个职位上还不够具体,并提出错误的问题。 我真正想知道的是,如何才能做到我想用性能计数器做的事情,还是根本无法做到?

编辑1

我正在运行Windows 10 Pro 1607 – 生成14393.479

当你对一台机器上的所有正在运行的进程做些什么的时候,Windows对于缓慢有点臭名昭着。 但是这太过分了。 在PerformanceCounter的状态中有些东西是烂的,我从这个问题中得到了第一个提示。 通过更改Console.WriteLine()调用,您可以在自己的测试程序中轻松地进行可视化:

  Console.Write($"Time taken to read {pcs.Count()} performance counters:"); Console.WriteLine($"{sw.ElapsedMilliseconds}ms, {GC.CollectionCount(2)} collections"); 

在我的机器上输出:

 Time taken to read 124 performance counters: 1633ms, 15 collections Time taken to read 124 performance counters: 923ms, 30 collections Time taken to read 124 performance counters: 928ms, 45 collections Time taken to read 124 performance counters: 934ms, 59 collections Time taken to read 124 performance counters: 922ms, 74 collections Time taken to read 124 performance counters: 925ms, 89 collections ...etc 

或者换句话说,对于PerformanceCounter.NextValue()的每个〜8调用,一个完整的垃圾回收。 哎哟。 是的,这会让你的计划陷入困境。

这是非常奇怪的行为,说得温和。 我在PerformanceCounter类本身找不到任何好的提示,代码看起来很无辜。 (C:\ Windows \ Microsoft.NET \ Framework \ v4.0.30319 \ PerfCounter.dll)很难看到一大块非托管代码,但是看它的依赖关系并不能提供令人信服的证据负责。 在v2.0.50727和v4.0.30319运行版本上都会发生这种情况,所以V4.x中的一个不幸的黑客并不能轻易解释它。 它不是8的很好的倍数,所以一个简单的计数器强制终结器运行并不容易解释它。 这不是本机性能计数器,使用WMI查询它不会触发任何收集。 它不是特定于内存计数器,查询“线程数”也是这样。 可能与Windows版本有关,我的是Win10版本1607(不能轻易测试另一个)。

微软需要参与这个。 我链接的问题的作者似乎已经创建了一个错误反馈报告 ,我添加了这个Q + A作为支持证据。 留意反馈报告,投票,希望他们会开始关注。 如果您不想等待,请直接与Microsoft支持部门联系。


同时,您可以使用System.Management命名空间。 WMI Code Creator实用程序非常方便自动生成代码:

 ... using System.Management; // Project > Add Reference required public static void QueryWorkingset() { ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\CIMV2", "SELECT Name, WorkingSetPrivate FROM Win32_PerfRawData_PerfProc_Process"); foreach (ManagementObject queryObj in searcher.Get()) { Console.WriteLine("{0}: {1}", queryObj["Name"], queryObj["WorkingSetPrivate"]); } } 

仍然没有速度恶魔,我的机器上每个进程大约需要1.0毫秒。 但是不像PerformanceCounter那样烧100%的内核,也不会强制收集。