Jak uzyskać użycie procesora w C #?

204

Chcę uzyskać ogólne całkowite wykorzystanie procesora dla aplikacji w języku C #. Znalazłem wiele sposobów zagłębiania się we właściwości procesów, ale chcę tylko użycia procesora przez procesy i całego procesora, tak jak w Menedżerze zadań.

W jaki sposób mogę to zrobić?

Peter Mortensen
źródło
36
Jak do cholery jest to poza tematem? Śmieszny.
Peter Moore,

Odpowiedzi:

205

Możesz użyć klasy PerformanceCounter z System.Diagnostics .

Zainicjuj w ten sposób:

PerformanceCounter cpuCounter;
PerformanceCounter ramCounter;

cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total");
ramCounter = new PerformanceCounter("Memory", "Available MBytes");

Spożywać w ten sposób:

public string getCurrentCpuUsage(){
            return cpuCounter.NextValue()+"%";
}

public string getAvailableRAM(){
            return ramCounter.NextValue()+"MB";
} 
CMS
źródło
80
Fajnie - ale wydaje się, że oryginalne źródło pochodzi stąd: zamov.online.fr/EXHTML/CSharp/CSharp_927308.html
Matt Refghi
19
Z tego, co odkryłem, musiałem użyć cpuCounter.NextValue () dwa razy, a między nimi musiałem spać (500)
Angel.King.47
Matt ma rację. Nawet w tym błędy, takie jak zapomnienie słowa kluczowego „return”.
Mark At Ramp51
8
tak, wygląda na kopię z tego linku, więc link do odniesienia do oryginału byłby fajnym stylem. Z drugiej strony, miło jest również CMS, aby udzielić odpowiedzi tutaj, więc leniwi programiści nie muszą przeszukiwać całego Google, aby znaleźć tę samą odpowiedź. : o)
BerggreenDK
13
Będziesz musiał dwukrotnie wywołać funkcję .NextValue, korzystając z połączenia System.Threading.Thread.Sleep pomiędzy (wystarczy 1000 ms). Zobacz blogs.msdn.com/b/bclteam/archive/2006/06/02/618156.aspx uzyskać więcej informacji na temat tego, dlaczego jest to konieczne, ale podsumowanie jest wysoki poziom, że trzeba dwóch próbek w celu obliczenia wartości, i musisz dać systemowi czasowi czas na zdobycie obu.
Cleggy
63

Nieco więcej niż wymagano, ale używam dodatkowego kodu czasowego do śledzenia i ostrzegania, jeśli użycie procesora wynosi 90% lub więcej przez dłuższy okres 1 minuty lub dłużej.

public class Form1
{

    int totalHits = 0;

    public object getCPUCounter()
    {

        PerformanceCounter cpuCounter = new PerformanceCounter();
        cpuCounter.CategoryName = "Processor";
        cpuCounter.CounterName = "% Processor Time";
        cpuCounter.InstanceName = "_Total";

                     // will always start at 0
        dynamic firstValue = cpuCounter.NextValue();
        System.Threading.Thread.Sleep(1000);
                    // now matches task manager reading
        dynamic secondValue = cpuCounter.NextValue();

        return secondValue;

    }


    private void Timer1_Tick(Object sender, EventArgs e)
    {
        int cpuPercent = (int)getCPUCounter();
        if (cpuPercent >= 90)
        {
            totalHits = totalHits + 1;
            if (totalHits == 60)
            {
                Interaction.MsgBox("ALERT 90% usage for 1 minute");
                totalHits = 0;
            }                        
        }
        else
        {
            totalHits = 0;
        }
        Label1.Text = cpuPercent + " % CPU";
        //Label2.Text = getRAMCounter() + " RAM Free";
        Label3.Text = totalHits + " seconds over 20% usage";
    }
}
Khalid Rahaman
źródło
7
Gdzie jest getRAMCounter ()?
Dieter B
1
cpuCounter.NextValuezwraca afloat . Po co więc przypisywać to do dynamic? Dlaczego więc zwracasz to dynamicjako object? Więc po co próbować przypisywać an objectdo intlinii int cpuPercent = getCPUCounter()? (Ten kod nie będzie się kompilował.)
Wyck
21

Po spędzeniu czasu na czytaniu kilku różnych wątków, które wydawały się dość skomplikowane, wpadłem na to. Potrzebowałem go dla 8-rdzeniowej maszyny, na której chciałem monitorować serwer SQL. Dla poniższego kodu podałem „sqlservr” jako appName.

private static void RunTest(string appName)
{
    bool done = false;
    PerformanceCounter total_cpu = new PerformanceCounter("Process", "% Processor Time", "_Total");
    PerformanceCounter process_cpu = new PerformanceCounter("Process", "% Processor Time", appName);
    while (!done)
    {
        float t = total_cpu.NextValue();
        float p = process_cpu.NextValue();
        Console.WriteLine(String.Format("_Total = {0}  App = {1} {2}%\n", t, p, p / t * 100));
        System.Threading.Thread.Sleep(1000);
    }
}

Wydaje się, że poprawnie mierzy% procesora używanego przez SQL na moim 8-rdzeniowym serwerze.

MtnManChris
źródło
total_cpu powinno być PerformanceCounter („Procesor”), a nie PerformanceCounter („Proces”) .. w przeciwnym razie otrzymasz tylko 100% * liczby rdzeni.
Steve Cook
3
Gdzie donejest prawda? Chyba że coś przeoczyłem, wydaje się, że jest to niekończąca się pętla:while(!done){...}
Manfred
@Manfred To jest rzeczywiście niekończąca się pętla
Jenny
16

W porządku, rozumiem! Dzięki za pomoc!

Oto kod, aby to zrobić:

private void button1_Click(object sender, EventArgs e)
{
    selectedServer = "JS000943";
    listBox1.Items.Add(GetProcessorIdleTime(selectedServer).ToString());
}

private static int GetProcessorIdleTime(string selectedServer)
{
    try
    {
        var searcher = new
           ManagementObjectSearcher
             (@"\\"+ selectedServer +@"\root\CIMV2",
              "SELECT * FROM Win32_PerfFormattedData_PerfOS_Processor WHERE Name=\"_Total\"");

        ManagementObjectCollection collection = searcher.Get();
        ManagementObject queryObj = collection.Cast<ManagementObject>().First();

        return Convert.ToInt32(queryObj["PercentIdleTime"]);
    }
    catch (ManagementException e)
    {
        MessageBox.Show("An error occurred while querying for WMI data: " + e.Message);
    }
    return -1;
}
buźiaki
źródło
Dodaj uzyskiwanie nazwy serwera zamiast wybranej zmiennej Serwer był lepszy. jak this.string nazwa_komputera = Environment.GetEnvironmentVariable („nazwa_komputera”);
Dave
5

CMS ma rację, ale także jeśli korzystasz z eksploratora serwerów w Visual Studio i bawisz się kartą licznika wydajności, możesz dowiedzieć się, jak uzyskać wiele przydatnych danych.

Tarki
źródło
3

Wydaje mi się, że to działa, na przykład czekanie, aż procesor osiągnie określony procent

var cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total");
int usage = (int) cpuCounter.NextValue();
while (usage == 0 || usage > 80)
{
     Thread.Sleep(250);
     usage = (int)cpuCounter.NextValue();
}
Jay Byford-Rew
źródło
dlaczego śpisz, gdy użycie wynosi 0?
watashiSHUN,
2

Ta klasa automatycznie odpytuje licznik co 1 sekundę i jest również bezpieczna dla wątków:

public class ProcessorUsage
{
    const float sampleFrequencyMillis = 1000;

    protected object syncLock = new object();
    protected PerformanceCounter counter;
    protected float lastSample;
    protected DateTime lastSampleTime;

    /// <summary>
    /// 
    /// </summary>
    public ProcessorUsage()
    {
        this.counter = new PerformanceCounter("Processor", "% Processor Time", "_Total", true);
    }

    /// <summary>
    /// 
    /// </summary>
    /// <returns></returns>
    public float GetCurrentValue()
    {
        if ((DateTime.UtcNow - lastSampleTime).TotalMilliseconds > sampleFrequencyMillis)
        {
            lock (syncLock)
            {
                if ((DateTime.UtcNow - lastSampleTime).TotalMilliseconds > sampleFrequencyMillis)
                {
                    lastSample = counter.NextValue();
                    lastSampleTime = DateTime.UtcNow;
                }
            }
        }

        return lastSample;
    }
}
Colin Breame
źródło
System.DateTimejest w rzeczywistości 8-bajtowym typem wartości, co oznacza, że ​​przypisania do DateTimezmiennej nie mają charakteru atomowego. Ten kod nie jest bezpieczny dla wątków na platformach 32-bitowych.
andrewjs
1

Nie podobało mi się dodawanie 1-sekundowego przeciągnięcia do wszystkich PerformanceCounterrozwiązań. Zamiast tego zdecydowałem się na WMIrozwiązanie. Powodem, dla którego istnieje 1 sekunda oczekiwania / przeciągnięcia, jest umożliwienie dokładnego odczytu podczas korzystania zPerformanceCounter . Jeśli jednak często wywołujesz tę metodę i odświeżasz te informacje, radzę, aby nie musieć ciągle ponosić tego opóźnienia ... nawet jeśli zastanawiasz się nad zrobieniem procesu asynchronicznego, aby go uzyskać.

Zacząłem od fragmentu stąd Zwracanie użycia procesora w WMI przy użyciu C # i dodałem pełne wyjaśnienie rozwiązania na moim blogu poniżej:

Uzyskaj wykorzystanie procesora we wszystkich rdzeniach w C # za pomocą WMI

atconway
źródło
Podaj tutaj odpowiedź zamiast linku do swojego bloga.
Herman
@Herman - nie tylko link do mojego bloga; Dałem wyjaśnienie 1. i podałem link do szczegółowej odpowiedzi poza postem tutaj.
atconway
rozwiązaniem w Twoim poście na blogu jest 12 linii kodu. Dlaczego nie uwzględnić tego w swojej odpowiedzi poza próbą nakłonienia ludzi do odwiedzenia Twojego bloga?
Herman
@Herman - Na czym polega problem z kliknięciem na link, ponieważ zawiera on szczegółowe wyjaśnienie; to jest idea opracowania części „dlaczego”? Również to ma 7 lat, tylko tak mówię. Trudno zapamiętać ten dokładny post, a ja byłem wtedy nowicjuszem na SO.
atconway
link może się zepsuć i o wiele łatwiej jest skanować odpowiedzi, gdy podstawowa treść jest wbudowana. Przepraszam, że jestem surowy w mojej drugiej odpowiedzi, nie jestem tutaj, aby ci przeszkadzać. :)
Herman
0
public int GetCpuUsage()
{
var cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total", Environment.MachineName);
cpuCounter.NextValue();
System.Threading.Thread.Sleep(1000); //This avoid that answer always 0
return (int)cpuCounter.NextValue();
}

Oryginalne informacje w tym linku https://gavindraper.com/2011/03/01/retrieving-accurate-cpu-usage-in-c/

araad1992
źródło