我不得不从网络上的极少数文章和 C++ 代码中解读这一点.我的问题是,对于问题 1,我所做的是否正确?有时返回的值是一个负数,这就是我乘以 -1 的原因.同样,我假设,因为文档很少,这就是我应该做的.我有以下代码:公共静态类处理器{[DllImport("kernel32.dll", SetLastError = true)]static extern bool GetSystemTimes(out ComTypes.FILETIME lpIdleTime, out ComTypes.FILETIME lpKernelTime, out ComTypes.FILETIME lpUserTime);私有静态时间跨度 _sysIdleOldTs;私有静态时间跨度 _sysKernelOldTs;私有静态时间跨度 _sysUserOldTs;静态处理器(){}公共静态无效测试(){ComTypes.FILETIME sysIdle、sysKernel、sysUser;if(GetSystemTimes(out sysIdle, out sysKernel, out sysUser)){TimeSpan sysIdleTs = GetTimeSpanFromFileTime(sysIdle);TimeSpan sysKernelTs = GetTimeSpanFromFileTime(sysKernel);TimeSpan sysUserTs = GetTimeSpanFromFileTime(sysUser);时间跨度 sysIdleDifenceTs = sysIdleTs.Subtract(_sysIdleOldTs);时间跨度 sysKernelDifenceTs = sysKernelTs.Subtract(_sysKernelOldTs);时间跨度 sysUserDifenceTs = sysUserTs.Subtract(_sysUserOldTs);_sysIdleOldTs = sysIdleTs;_sysKernelOldTs = sysKernelTs;_sysUserOldTs = sysUserTs;时间跨度系统 = sysKernelDiffenceTs.Add(sysUserDifenceTs);双 cpuUsage = (((system.Subtract(sysIdleDiffenceTs).TotalMilliseconds) * 100)/system.TotalMilliseconds);如果 (cpuUsage 问题 2:无论如何,我是否可以将程序中的线程与 Windows 任务管理器的线程同步,以便将测量数字(例如 CPU 使用率)与上述代码进行匹配?我的意思是,如果您打开 Windows 任务管理器,您会注意到它每秒轮询一次 - 实际上它不需要少于此时间.我想要做的是与我的线程匹配时间.所以当 Windows 任务管理器轮询时,我的线程轮询.一些注意事项:我不想使用性能计数器或 .NET 内置方法.事实上,我相信 - 从我读到的内容来看,.NET 没有计算机器上 CPU 使用率的方法,否则需要性能计数器.性能计数器有开销,此外还会使 GC 增长,更不用说调用下一个结果的延迟.虽然我的软件不需要具有实时性能,但我确实需要它具有响应性并尽可能少地使用 CPU 时间.可以在不到一毫秒的时间内调用和返回上述代码.事实上,在我的开发机器上,时间跨度差异显示为 0ms.我认为性能计数器没有那么灵敏.如果你好奇,我的软件正在收集许多项目,CPU、内存、事件日志项目等,其中所有这些都需要在 SQL CE 中收集并存储在 SQL CE 中,在下一次轮询之前,1 秒后.然而,每个任务、项目都在自己的线程上,以促进这一点.此外,上面的代码并没有进行任何优化,您会注意到我还没有对其进行评论.原因是我想在优化等之前确保它是正确的.更新 1根据我一路上的评论,我删除了额外的系统"时间跨度,因为它不是必需的,并修改了检索CPU 使用率"的行并进行了适当的转换.int cpuUsage = (int)(((sysKernelDifferenceTs.Add(sysUserDifferenceTs).Subtract(sysIdleDifferenceTs).TotalMilliseconds) * 100.00)/sysKernelDifferenceTs.Add(sysUserDifferenceTs).TotalMilliseconds);虽然我仍然不确定公式.虽然它似乎非常准确,但它有时会返回一个负数,这就是为什么我将它乘以 -1(如果是这种情况).毕竟,没有 -2% CPU 使用率之类的东西.更新 2所以我使用System.Diagnostics.PerformanceCounter"做了一个简单的测试.虽然非常方便并且完全按照预期执行,但确实会产生开销.以下是我的观察:性能计数器的初始化时间要长得多.在我的 i7 2.6 Ghz 上大约多出三秒.性能计数器似乎还仅仅通过使用它就增加了大约 5MB 的 RAM 使用量.我的意思是:使用上面的代码,我的应用程序最大内存为 7.5MB.使用性能计数器,它开始"为 12.5MB.在 5 秒的时间里,我的线程运行了 5 次 - 每秒一次,我的应用程序的内存增加了 1 MB,这种增加与时间一致,尽管它确实稳定了,无论如何,在我的情况下,3-4MB 以上开始.所以我的应用程序通常是 7.5MB ram,上面的代码,PC 代码稳定在 16.5MB ram - 比上面的代码增加了 9MB.注意:上面的代码不会导致这种增加.因此,如果您的应用程序是以资源使用和时间为关键的方式构建的,我建议您不要使用性能计数器,因为这些原因.否则就继续吧,一切顺利.至于我的应用程序,性能计数器将不利于我的软件的用途. 解决方案 我认为您的公式中存在错误.您想基本上计算 CPU 使用率:CPU 使用率 = KernelTimeDiff + UserTimeDiff-----------------------------------------KernelTimeDiff + UserTimeDiff + IdleTimeDiff因此,对您的代码进行如下快速修改://TimeSpan system = sysKernelDiffenceTs.Add(sysUserDiffenceTs);//双cpuUsage = (((system.Subtract(sysIdleDiffenceTs).TotalMilliseconds) * 100)/system.TotalMilliseconds);时间跨度总时间 = sysKernelDiffenceTs.Add(sysUserDifenceTs);totaltime = totaltime.Add(sysIdleDifferenceTs);int cpuUsage = 100 - (sysIdleDifferenceTs.TotalMilliseconds * 100)/totaltime.TotalMilliseconds;Console.WriteLine("CPU:" + cpuUsage + "%");您最初将 cpuUsage 声明为Double".我不确定您是否想要浮点精度,但是在您的代码中,您肯定没有得到除整数精度以外的任何东西,因为赋值语句只是在进行整数数学运算.如果您需要更高的计算精度,您可以通过混合一些浮点来轻松获得它:Double cpuUsage = 100.0 - (sysIdleDifferenceTs.TotalMilliseconds * 100.0)/totaltime.TotalMilliseconds;此外,关于与任务管理器同步.据我了解,任务管理器使用性能计数器.(我怀疑 GetSystemTimes 在幕后进行性能计数器调用,但也许不是).而且我不确定您为什么不使用性能计数器.% Process Time"计数器是一个即时样本计数器,不需要计算与先前结果的差异.(每个逻辑 CPU 有一个).使用 PDH 辅助函数而不是旧的注册表项 api 来获取它.您可以从非托管 C/C++ DLL 执行此操作,该 DLL 将GetCpuUsage"函数导出回您的 C# 代码.但我不知道为什么你不能直接从 C# 调用 PDH 函数.我不知道你说的这个开销.我也不确定我是否理解您提到的调用下一个结果的延迟".this is a two part question, I wanted to post my code here on stack to help others with the same task.Question 1:I have a subset of code, which I believe, is correctly measuring CPU usage (across as many cores in the system, as per times retrieved) as per the measurement interval - I use 1 second in the thread call.I had to decipher this from the very few articles on the web and from C++ code. My question is, for question 1, is this correct what I have done?Sometimes the value returned is a minus figure which is why I multiply by -1. Again, I am assuming, since there is very little documentation, that this is what I should be doing.I have the following code:public static class Processor{ [DllImport("kernel32.dll", SetLastError = true)] static extern bool GetSystemTimes(out ComTypes.FILETIME lpIdleTime, out ComTypes.FILETIME lpKernelTime, out ComTypes.FILETIME lpUserTime); private static TimeSpan _sysIdleOldTs; private static TimeSpan _sysKernelOldTs; private static TimeSpan _sysUserOldTs; static Processor() { } public static void Test() { ComTypes.FILETIME sysIdle, sysKernel, sysUser; if(GetSystemTimes(out sysIdle, out sysKernel, out sysUser)) { TimeSpan sysIdleTs = GetTimeSpanFromFileTime(sysIdle); TimeSpan sysKernelTs = GetTimeSpanFromFileTime(sysKernel); TimeSpan sysUserTs = GetTimeSpanFromFileTime(sysUser); TimeSpan sysIdleDiffenceTs = sysIdleTs.Subtract(_sysIdleOldTs); TimeSpan sysKernelDiffenceTs = sysKernelTs.Subtract(_sysKernelOldTs); TimeSpan sysUserDiffenceTs = sysUserTs.Subtract(_sysUserOldTs); _sysIdleOldTs = sysIdleTs; _sysKernelOldTs = sysKernelTs; _sysUserOldTs = sysUserTs; TimeSpan system = sysKernelDiffenceTs.Add(sysUserDiffenceTs); Double cpuUsage = (((system.Subtract(sysIdleDiffenceTs).TotalMilliseconds) * 100) / system.TotalMilliseconds); if (cpuUsage < 0) { Console.WriteLine("CPU: " + ((int) (cpuUsage)*-1) + "%"); } else { Console.WriteLine("CPU: " + (int) (cpuUsage) + "%"); } Console.WriteLine(""); } else { Console.WriteLine("Couldn't get CPU usage!"); Console.WriteLine(""); } } private static TimeSpan GetTimeSpanFromFileTime(ComTypes.FILETIME time) { return TimeSpan.FromMilliseconds((((ulong)time.dwHighDateTime << 32) + (uint)time.dwLowDateTime) * 0.000001); }}Question 2:Is there anyway for me to sync a thread, in my program, with that of the Windows Task Manager, for the purpose of matching measurement figure e.g CPU Usage with the above code?What I mean is, if you open Windows Task Manager, you will notice that it polls every second - which in reality it doesn't need to be less than that. What I want to do is match the timing with my thread.So when Windows Task Manager polls, my thread polls.Some notes:I didn't want to use Performance Counters or .NET built in methods. In fact, I believe - from what I have read, .NET doesn't have methods for calculating the CPU usage on a machine, that Performance counters are required for this otherwise.Performance counters have overhead and in addition make the GC grow, not to mention the delay in calling the next result. While my software does not need to be real-time performance I do need it to be as responsive and use as little CPU time as possible. The above code can be called and returned in less than a millisecond. In fact on my development machine, the time-span difference shows 0ms. I don't believe Performance Counters are as responsive.In case you are curious, my software is gathering a number of items, CPU, Memory, Event Log items etc. of which these all need to be gathered and stored, in SQL CE, before the next poll, 1 second away. Each task, item, however is on its own thread to facilitate this.Also, the code above is not optimized in anyway and you will notice I have yet to comment it also. The reason being is I want to make sure it is correct before optimization etc.Update 1As per a coment I made down the way, I removed the extra "System" timespan as it is not required and modified the line that retrieves the "CPU Usage" and cast it appropriately.int cpuUsage = (int)(((sysKernelDifferenceTs.Add(sysUserDifferenceTs).Subtract(sysIdleDifferenceTs).TotalMilliseconds) * 100.00) / sysKernelDifferenceTs.Add(sysUserDifferenceTs).TotalMilliseconds);Though I am still unsure of the formula. While it seems to be highly accurate it does on occasion return a minus figure which is why I multiply it by -1 if that is the case. After all, there is no such thing a -2% CPU usage etc.Update 2So I did a simple test using "System.Diagnostics.PerformanceCounter". While incredibly handy and does exactly what it is intended to do it does create overhead.Here are my observations:It took the Performance Counter that much longer to initialize. In the order of roughly three seconds longer on my i7 2.6 Ghz.The performance counter also seemed to add on another approx 5MB of RAM usage simply by using it. What I mean by this is: With the code above ,my app maxes out at 7.5MB ram. With the performance counter it "starts" at 12.5MB.Over the space of 5 seconds, where my thread ran 5 times - once per second, the memory of my app had grown by 1 MB and this increase is consistent with time, although it does level out, in my case anyway, 3-4MB above starting. So where my app is usually 7.5MB ram with the code above, the PC code leveled out at 16.5 MB ram - an increase of 9MB over the code above. Note: The code above does not cause this increase.So, if your application was built in a manner where resource usage and timing is key I would suggest against using Performance counters because of these reasons. Otherwise go ahead as it works without all the mess.As for my app, performance counters will be detrimental to my software's purpose. 解决方案 I think you have a bug in your formula. You want to basically compute CPU usage as this:CPU Usage = KernelTimeDiff + UserTimeDiff -------------------------------------------- KernelTimeDiff + UserTimeDiff + IdleTimeDiffThus, a quick mod to your code as follows: // TimeSpan system = sysKernelDiffenceTs.Add(sysUserDiffenceTs); //Double cpuUsage = (((system.Subtract(sysIdleDiffenceTs).TotalMilliseconds) * 100) / system.TotalMilliseconds); TimeSpan totaltime = sysKernelDiffenceTs.Add(sysUserDiffenceTs); totaltime = totaltime.Add(sysIdleDifferenceTs); int cpuUsage = 100 - (sysIdleDifferenceTs.TotalMilliseconds * 100) / totaltime.TotalMilliseconds; Console.WriteLine("CPU: " + cpuUsage + "%");You originally declared cpuUsage as "Double". I'm not sure if you wanted floating point precision, but in your code, you definitely weren't getting anything other than integer precision because the assignment statement was just doing integer math. If you need higher precision from the computation, you could easily get it by mixing in some floating point:Double cpuUsage = 100.0 - (sysIdleDifferenceTs.TotalMilliseconds * 100.0) /totaltime.TotalMilliseconds;Also, in regards to being in sync with Task Manager. Task Manager, as I understand it, uses perf counters. (And I would suspect that GetSystemTimes is making perf counter calls under the hood, but perhaps not). And I'm not sure why you wouldn't use perf counters either. The "% Process Time" counter is an instant sample counter that doesn't require computing a diff with a previous result. (There's one per logical cpu). Use the PDH helper functions instead of the legacy registry key apis to get at it. You can do this from an unmanaged C/C++ DLL that exports a "GetCpuUsage" function back to your C# code. But I don't know why you couldn't just PInvoke the PDH functions from C# either. I don't know about this overhead that you speak of. I'm not sure I understand your reference to " the delay in calling the next result" either. 这篇关于C# 系统 CPU 使用率和与 Windows 任务管理器同步的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!