2010-02-23 14 views
13

Ho un'applicazione che richiede un uso intensivo della CPU. Quando i dati vengono elaborati su un singolo thread, l'utilizzo della CPU passa al 100% per molti minuti. Quindi le prestazioni dell'applicazione sembrano essere vincolate dalla CPU. Ho multithreading la logica dell'applicazione, che si traducono in un aumento delle prestazioni complessive. Tuttavia, l'utilizzo della CPU difficilmente supera il 30% -50%. Mi aspetto che la CPU (e molti core) vada al 100% dal momento che elaboro molti set di dati allo stesso tempo.Quali sono i motivi per cui l'utilizzo della CPU non va al 100% con C# e APM?

Di seguito è riportato un esempio semplificato della logica che utilizzo per avviare i thread. Quando eseguo questo esempio, la CPU va al 100% (su una macchina 8/16 core). Tuttavia, la mia applicazione che utilizza lo stesso modello non lo fa.

public class DataExecutionContext 
{ 
    public int Counter { get; set; } 

    // Arrays of data 
} 

static void Main(string[] args) 
{ 
    // Load data from the database into the context 
    var contexts = new List<DataExecutionContext>(100); 
    for (int i = 0; i < 100; i++) 
    { 
     contexts.Add(new DataExecutionContext()); 
    } 

    // Data loaded. Start to process. 
    var latch = new CountdownEvent(contexts.Count); 
    var processData = new Action<DataExecutionContext>(c => 
    { 
     // The thread doesn't access data from a DB, file, 
     // network, etc. It reads and write data in RAM only 
     // (in its context). 
     for (int i = 0; i < 100000000; i++) 
      c.Counter++; 
    }); 

    foreach (var context in contexts) 
    { 
     processData.BeginInvoke(context, new AsyncCallback(ar => 
     { 
      latch.Signal(); 
     }), null); 
    } 

    latch.Wait(); 
} 

Ho ridotto il numero di blocchi al minimo (solo il blocco è bloccato). Il modo migliore che ho trovato è stato quello di creare un contesto in cui un thread può leggere/scrivere in memoria. I contesti non sono condivisi tra altri thread. I thread non possono accedere al database, ai file o alla rete. In altre parole, ho profilato la mia domanda e non ho trovato alcun collo di bottiglia.

Perché l'utilizzo della CPU della mia applicazione non aumenta del 50%? È lo schema che uso? Dovrei creare il mio thread invece di usare il pool di thread .Net? C'è qualche trucchetto? C'è qualche strumento che potresti raccomandarmi per trovare il mio problema?

Grazie!

+0

Possibile, ma poco probabile sarebbe che il codice sta provocando un sacco di garbage collection, che richiede una certa quantità di sincronizzazione. –

risposta

6

Ci sono molte cose che potrebbero, potenzialmente, causare questo comportamento.

Innanzitutto, che tipo di CPU hai? Se hai un processore i7 o simile, il sistema operativo vedrà che questo ha 8 core, quando in realtà ha 4 core con 2 hyperthread/core. Per la maggior parte delle operazioni, l'hyperthreading non fornisce la stessa scalabilità di un secondo core, anche se il sistema operativo lo vede in questo modo. Ho avuto questa causa il mio utilizzo complessivo della CPU apparire inferiore al sistema operativo ...

In secondo luogo, è possibile che si verifichi una forma di condivisione vera. Hai detto che hai un blocco - anche se è ridotto al minimo, i blocchi potrebbero impedirti di pianificarlo efficacemente.

Inoltre, in questo momento, stai pianificando tutti i 100 elementi di lavoro, direttamente in primo piano. L'os sta per avere una pagina dentro e fuori quei 100 thread. Si consiglia di limitare questo per consentire solo un certo numero di elaborare in un dato momento. Questo è molto più semplice utilizzando la nuova libreria parallela Task (basta usare Parallel.ForEach con un'impostazione ParallelOptions per avere un numero massimo di thread), ma può essere eseguita autonomamente.

Dato che si stanno pianificando tutti e 100 gli elementi per elaborare simultaneamente, il paging potrebbe ostacolare la capacità di ottenere il massimo rendimento.

Inoltre, se stai facendo un altro lavoro "più reale", potresti avere problemi di condivisione falsi, specialmente se lavori con array o raccolte condivise (anche se gli elementi che stai elaborando sono non condiviso).

Si consiglia di eseguire questo sotto il profiler della concorrenza in VS 2010 - vi fornirà un quadro molto più chiaro di ciò che sta accadendo.

+0

Ho provato su molte macchine: Core Duo (utilizzo ~ 80-90%), i7 (utilizzo ~ 50%), Dual Xeon L5520 (utilizzo ~ 40-50%). – Martin

+0

Dal momento che sei dell'80-90% sul duo di base e inferiore sugli altri, sembra che tu abbia problemi di condivisione falsi o veri. È possibile che si verifichi una condivisione errata se si tenta di utilizzare i dati che si trovano troppo strettamente nella memoria, da più thread: la vera condivisione è dovuta al blocco ... –

+1

Ho trovato l'articolo su MSDN su False Sharing (http: // msdn. microsoft.com/en-us/magazine/cc872851.aspx) e sembra che potrebbe essere il mio problema ... Non sono ancora sicuro di comprendere completamente False Condivisione. Come lo hai capito? – Martin

2

Questo è speculationg senza vedere l'applicazione, ma se l'applicazione sta facendo qualsiasi elaborazione che si occupa di file, database, creazione di molti oggetti (richiesta di memoria), lavoro con dispositivi di rete, o dispositivi hardware di qualsiasi tipo, quindi quei fattori potrebbe limitare l'applicazione a raggiungere il 100% di utilizzo della CPU. Questo combinato con il cambio di thread potrebbe anche essere un fattore.

Si dice che si sta utilizzando il modello dell'esempio fornito, ma si dice che l'esempio raggiunge il 100% di utilizzo, ma l'applicazione non lo fa. Quindi c'è qualche differenza lì, e dovresti provare a descrivere più dettagliatamente cosa sta facendo la tua applicazione. Il 50% di utilizzo non è male. Molte applicazioni funzionano al 50% su CPU Intel con hyper-thread e funzionano comunque bene. Se l'applicazione non raggiunge il 100% di utilizzo della cpu e stai ancora ottenendo buone prestazioni, allora direi che in realtà è una buona cosa, perché significa che hai un po 'di spazio perché non è più legato alla CPU. Ciò significa che i casi in cui altre cose potrebbero richiedere tempo di CPU, la tua applicazione non ne risentirà più. Se fosse al 100% di utilizzo, vedresti le prestazioni delle applicazioni vacillare quando altri processi utilizzano in modo attivo la CPU.

0

se si stanno facendo un sacco di piccole allocazioni di memoria - heap gestito può diventare una risorsa condivisa che blocca i fili e rallenta il processo e, quindi, l'utilizzo della CPU

Problemi correlati