Como obter o uso da CPU em c #?


Respostas:


205

Você pode usar a classe PerformanceCounter do System.Diagnostics .

Inicialize assim:

PerformanceCounter cpuCounter;
PerformanceCounter ramCounter;

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

Consumir assim:

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

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

80
Nice - mas a fonte original parece ser a partir daqui: zamov.online.fr/EXHTML/CSharp/CSharp_927308.html
Matt Refghi

19
Pelo que eu descobri, eu tinha que usar cpuCounter.NextValue () duas vezes e entre eles eu tinha que Dormir (500)
Angel.King

Matt está certo. Mesmo incluindo os erros, como esquecer a palavra-chave "return".
usar o seguinte código

8
sim, parece uma cópia desse link; portanto, um link para referência do original teria sido um estilo legal. Por outro lado, também é bom que o CMS forneça a resposta aqui, para que desenvolvedores preguiçosos não precisem pesquisar em todo o Google para encontrar a mesma resposta. : o)
BerggreenDK

13
Você precisará chamar .NextValue duas vezes, com uma chamada System.Threading.Thread.Sleep no meio (1000ms deve ser suficiente). Consulte blogs.msdn.com/b/bclteam/archive/2006/06/02/618156.aspx para obter mais informações sobre por que isso é necessário, mas o resumo de alto nível é que você precisa de duas amostras para calcular o valor, e você precisa dar um tempo ao sistema operacional para obter os dois.
Cleggy

63

Um pouco mais do que foi solicitado, mas eu uso o código de timer extra para rastrear e alertar se o uso da CPU é 90% ou mais por um período prolongado de 1 minuto ou mais.

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
Onde está o getRAMCounter ()?
Dieter B

1
cpuCounter.NextValueretorna afloat . Então, por que atribuí-lo a um dynamic? Então, por que retornar isso dynamiccomo um object? Então, por que tentar atribuir um objecta um intna linha int cpuPercent = getCPUCounter()? (Esse código não irá compilar.)
Wyck

21

Depois de passar algum tempo lendo alguns tópicos diferentes que pareciam bastante complicados, eu vim com isso. Eu precisava dele para uma máquina de 8 núcleos onde queria monitorar o servidor SQL. Para o código abaixo, passei "sqlservr" como 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);
    }
}

Parece medir corretamente a% de CPU usada pelo SQL no meu servidor de 8 núcleos.


total_cpu deve ser PerformanceCounter ("Processor"), não PerformanceCounter ("Process"). Caso contrário, você obtém 100% * do número de núcleos.
Steve Cook

3
Onde você define donea verdade? A menos que eu tenha esquecido alguma coisa, isso parece ser um loop infinito:while(!done){...}
Manfred

@Manfred Na verdade, é um anel sem fim
Jenny

16

Está tudo bem, eu entendi! Obrigado pela ajuda!

Aqui está o código para fazer isso:

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

Adicionar a obtenção do nome do servidor em vez da variável selectedServer foi melhor. como este.string nome_do_computador = Environment.GetEnvironmentVariable ("nome_do_computador");
Dave


5

O CMS está certo, mas também se você usar o server explorer no visual studio e brincar com a guia do contador de desempenho, poderá descobrir como obter muitas métricas úteis.


3

Isso parece funcionar para mim, um exemplo de espera até que o processador atinja uma certa porcentagem

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

por que você está dormindo quando o uso é 0?
WatsonSHUN

2

Essa classe pesquisa automaticamente o contador a cada 1 segundo e também é segura para threads:

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.DateTimeé na verdade um tipo de valor de 8 bytes, o que significa que as atribuições a uma DateTimevariável não são atômicas. Este código não é seguro para threads em plataformas de 32 bits.
andrewjs

1

Eu não gostei de ter que adicionar no estande de 1 segundo a todas as PerformanceCountersoluções. Em vez disso, optei por usar uma WMIsolução. A razão pela qual a espera / travamento de 1 segundo existe é permitir que a leitura seja precisa ao usar umPerformanceCounter . No entanto, se você chamar esse método com frequência e atualizar essas informações, aconselho a não ter que sofrer constantemente esse atraso ... mesmo que esteja pensando em fazer um processo assíncrono para obtê-lo.

Comecei com o trecho daqui Retornando o uso da CPU no WMI usando C # e adicionei uma explicação completa da solução no meu blog abaixo:

Obter uso da CPU em todos os núcleos em C # usando WMI


Inclua a resposta aqui em vez de vincular ao seu blog.
Herman

@ Herman - eu não apenas criei um link para o meu blog; Dei uma explicação primeiro e comecei a fornecer um link para uma resposta detalhada além do post aqui.
atconway

a solução em seu blog é como 12 linhas de código. Por que não incluir isso em sua resposta, além de tentar levar as pessoas a visitar seu blog?
Herman

@ Herman - Qual é o problema em clicar no link, pois contém uma explicação detalhada; essa é a ideia da elaboração da porção 'por que'? Também isso tem 7 anos, apenas dizendo. Difícil lembrar esse post exato e eu ser um novato no SO naquela época.
atconway

o link pode ficar quebrado e é muito mais fácil verificar as respostas quando o conteúdo principal está embutido. Desculpe por ser duro na minha outra resposta, não estou aqui para lhe dar um tempo difícil. :)
Herman

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.