在C#中异步检索CPU使用率

3

我希望用c#获取我的系统的cpu使用率。我读到了必须调用方法NextValue(),然后等待大约一秒钟再次调用NextValue()方法。

为了不延迟我的UI线程,我想以异步方式实现,因此编写了以下代码:

    public Task<float> GetCpuPerformanceAsync()
    {
        return Task.Run(() =>
        {
            CpuPerformance.NextValue();
            Task.Delay(1000);
            return CpuPerformance.NextValue();
        });
    }

这是 CpuPerformance 的声明。
CpuPerformance = new PerformanceCounter("Processor Information", "% Processor Time", "_Total");

在第一次调用上述异步方法时,它会返回实际的CPU使用情况,但是在几秒钟后再次调用它时,它只显示0或100,这与任务管理器中显示的使用情况不一致。请问有人能帮我解决这个问题吗?

1
它真的会延迟吗?我期望需要 await Task.Delay(1000) ... - Fildor
1
请注意,您没有等待 Task.Delay 的调用,因此它实际上不会等待任何时间。您可能想要使用 public async Task<float> GetCpuPerformanceAsync() { CpuPerformance.NextValue(); await Task.Delay(1000); return CpuPerformance.NextValue(); }。话虽如此,我不确定调用 NextValue(),然后丢弃结果,等待一段时间,再次调用它是否会给您带来任何好处。 - canton7
2
“我已经阅读过,我必须……” - 你能给出你阅读到这个信息的参考资料吗? - Fildor
1
@Fildor 在这里阅读:https://dev59.com/YnI95IYBdhLWcg3wtwf4 - Marcel Müller
@Fildor 因为我不明白你所说的“热起来”是什么意思?你能否请展示一下你的意思? - Marcel Müller
显示剩余4条评论
2个回答

5

这是对@Fildor答案的一种替代方案,使用了他们提出的技术,但避免了第一次访问CpuTimeInPercent时挂起线程的情况。

public static class Helper
{
    private static readonly Task<PerformanceCounter> performanceCounter = GetCounter();

    private static async Task<PerformanceCounter> GetCounter()
    {
        PerformanceCounter pc = new PerformanceCounter("Processor Information", "% Processor Time", "_Total");
        // "warm up"
        pc.NextValue();
        await Task.Delay(1000);
        // return ready-to-use instance
        return pc;
    }

    public static async Task<float> GetCpuTimeInPercentAsync()
    {
        var counter = await performanceCounter;
        return counter.NextValue();
    }
}

performanceCounter第一次执行之前(可能是当程序集被加载时,也可能是在调用GetCounter()时),GetCounter()将开始执行。如果在其进行热身期间调用GetCpuTimeInPercentAsync,则它将等待直到完成并获取CPU使用情况。如果您在热身后或随后调用它,则会立即返回CPU使用情况。


1
太好了!我还是会留下我的代码,只是为了展示“Lazy”的用法... - Fildor
2
@Fildor 请继续——我认为OP接受您的答案是正确的,因为您做了很多工作。我只是想展示如何使用任务完成它,而这对于评论来说有点太长了。 - canton7

3

很遗憾,dotnetfiddle不允许我使用PerformanceCounters,但无论如何这应该仍然有效:

public class Helper // Of course, you do not necessarily need an extra class ...
{
    // Lazy Pattern: Will create an instance on first usage.
    private static Lazy<PerformanceCounter> CpuPerformance = new Lazy<PerformanceCounter>(() => {
        // this will be used as factory to create the instance ...
        // 1. create counter
        PerformanceCounter pc = new PerformanceCounter("Processor Information", "% Processor Time", "_Total");
        // "warm up"
        pc.NextValue();
        Thread.Sleep(1000);
        // return ready-to-use instance
        return pc;
        // ^^ this will be executed only _once_.
    });

    // Read-Only Property uses Lazy to ensure instance exists, then use it.
    public static float CpuTimeInPercent {
        get { return CpuPerformance.Value.NextValue(); }
    }
}

使用方法:

Console.WriteLine("Performance: {0}%", Helper.CpuTimeInPercent);

3
注意,这会暂停您的线程一秒钟,当它第一次访问CpuTimeInPercent时,这显然不是您在问题中想要避免的。 - canton7
1
我猜你可以调整这个,以便在创建时不阻塞UI线程。这只是为了展示源代码中所谓的“预热”,就像我所说的那样。@canton7 - Fildor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接