Comment obtenir l'utilisation du processeur en C #?


204

Je veux obtenir l'utilisation totale totale du processeur pour une application en C #. J'ai trouvé de nombreuses façons de creuser dans les propriétés des processus, mais je ne veux que l'utilisation du processeur des processus et le processeur total comme vous obtenez dans le TaskManager.

Comment je fais ça?



36
Comment diable est-ce hors sujet? Ridicule.
Peter Moore

Réponses:


205

Vous pouvez utiliser la classe PerformanceCounter de System.Diagnostics .

Initialisez comme ceci:

PerformanceCounter cpuCounter;
PerformanceCounter ramCounter;

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

Consommer comme ceci:

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

public string getAvailableRAM(){
            return ramCounter.NextValue()+"MB";
} 

80
Sympa - mais la source originale semble provenir d'ici: zamov.online.fr/EXHTML/CSharp/CSharp_927308.html
Matt Refghi

19
D'après ce que j'ai découvert, j'ai dû utiliser deux fois cpuCounter.NextValue () et entre eux j'ai dû dormir (500)
Angel.King.47

Matt a raison. Même en incluant les bugs, comme oublier le mot-clé "return".
Mark At Ramp51

8
oui, il ressemble à une copie de ce lien, donc un lien de référence de l'original aurait été sympa. D'un autre côté, c'est aussi agréable de CMS pour fournir la réponse ici afin que les développeurs paresseux n'aient pas à chercher partout sur Google pour trouver la même réponse. : o)
BerggreenDK

13
Vous devrez appeler .NextValue deux fois, avec un appel System.Threading.Thread.Sleep entre les deux (1000 ms devraient suffire). Voir blogs.msdn.com/b/bclteam/archive/2006/06/02/618156.aspx pour plus d'informations sur la raison pour laquelle cela est requis, mais le résumé de haut niveau est que vous avez besoin de deux échantillons pour calculer la valeur, et vous devez donner au système d'exploitation un temps pour obtenir les deux.
Cleggy

63

Un peu plus que ce qui était requis, mais j'utilise le code de minuterie supplémentaire pour suivre et alerter si l'utilisation du processeur est de 90% ou plus pendant une période prolongée de 1 minute ou plus.

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";
    }
}

7
Où est le getRAMCounter ()?
Dieter B du

1
cpuCounter.NextValuerenvoie afloat . Alors pourquoi l'attribuer à un dynamic? Alors pourquoi retourner ça en dynamictant que object? Alors pourquoi essayer d'assigner un objectà un intdans la ligne int cpuPercent = getCPUCounter()? (Ce code ne sera pas compilé.)
Wyck

21

Après avoir passé un peu de temps à lire quelques fils différents qui semblaient assez compliqués, j'ai trouvé cela. J'en avais besoin pour une machine à 8 cœurs où je voulais surveiller le serveur SQL. Pour le code ci-dessous, j'ai passé "sqlservr" comme 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);
    }
}

Il semble mesurer correctement le% de CPU utilisé par SQL sur mon serveur 8 cœurs.


total_cpu doit être PerformanceCounter ("Processor"), pas PerformanceCounter ("Process") .. sinon vous obtenez simplement 100% * de cœurs.
Steve Cook

3
Où mettez-vous doneà vrai? À moins que j'aie oublié quelque chose, cela semble être une boucle sans fin:while(!done){...}
Manfred

@Manfred C'est en effet une boucle sans fin
Jenny

16

C'est bon, je l'ai! Merci de votre aide!

Voici le code pour le faire:

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;
}

L'ajout du nom du serveur au lieu de la variable selectedServer était préférable. comme ceci.string nom_ordinateur = Environment.GetEnvironmentVariable ("nom_ordinateur");
Dave


5

CMS a raison, mais aussi si vous utilisez l'explorateur de serveurs dans Visual Studio et jouez avec l'onglet du compteur de performances, vous pouvez trouver comment obtenir de nombreuses mesures utiles.


3

Cela semble fonctionner pour moi, un exemple pour attendre que le processeur atteigne un certain pourcentage

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();
}

pourquoi dormez-vous quand l'utilisation est 0?
watashiSHUN

2

Cette classe interroge automatiquement le compteur toutes les 1 secondes et est également thread-safe:

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;
    }
}

System.DateTimeest en fait un type de valeur de 8 octets, ce qui signifie que les affectations à une DateTimevariable ne sont pas atomiques. Ce code n'est pas thread-safe sur les plates-formes 32 bits.
andrewjs

1

Je n'ai pas aimé avoir à ajouter dans le décrochage 1 seconde à toutes les PerformanceCountersolutions. Au lieu de cela, j'ai choisi d'utiliser une WMIsolution. La raison pour laquelle l'attente / décrochage de 1 seconde existe est de permettre à la lecture d'être précise lors de l'utilisation d'unPerformanceCounter . Cependant, si vous appelez souvent cette méthode et actualisez ces informations, je vous conseille de ne pas avoir à subir constamment ce retard ... même si vous envisagez de faire un processus asynchrone pour l'obtenir.

J'ai commencé avec l'extrait d'ici Retour de l'utilisation du processeur dans WMI en utilisant C # et j'ai ajouté une explication complète de la solution sur mon blog ci-dessous:

Obtenir l'utilisation du processeur sur tous les cœurs en C # à l'aide de WMI


Veuillez inclure la réponse ici au lieu de créer un lien vers votre blog.
Herman

@Herman - Je ne me suis pas contenté de créer un lien vers mon blog; J'ai donné une explication en premier et j'ai continué à fournir un lien pour une réponse approfondie au-delà du post ici.
atconway

la solution dans votre article de blog est comme 12 lignes de code. Pourquoi ne pas inclure cela dans votre réponse autre que d'essayer d'amener les gens à visiter votre blog?
Herman

@Herman - Quel est le problème en cliquant sur le lien car il contient une explication détaillée; c'est l'idée de l'élaboration de la partie «pourquoi»? C'est aussi 7 ans, juste pour dire. Difficile de se souvenir de ce message exact et de moi étant un nouveau sur SO à l'époque.
atconway

le lien pourrait être rompu, et il est beaucoup plus facile d'analyser les réponses lorsque le contenu principal est en ligne. Désolé d'être sévère dans mon autre réponse, je ne suis pas ici pour vous donner du fil à retordre. :)
Herman

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.