40

Sto usando Parallel.ForEach e sto facendo alcuni aggiornamenti del database, ora senza impostare MaxDegreeOfParallelism, un computer con processore dual core risulta in timeout client SQL, mentre in altri casi il processore quad core in qualche modo non ha timeout.Che cosa fa MaxDegreeOfParallelism?

Ora non ho il controllo su quale tipo di core del processore sono disponibili dove viene eseguito il mio codice, ma ci sono alcune impostazioni che posso modificare con MaxDegreeOfParallelism che probabilmente eseguirà meno operazioni contemporaneamente e non determinerà timeout?

Posso aumentare i timeout ma non è una buona soluzione, se sulla CPU inferiore posso elaborare meno operazioni contemporaneamente, che metterà meno carico sulla cpu.

Ok Ho letto anche tutti gli altri post e MSDN, ma impostando MaxDegreeOfParallelism su un valore inferiore, le mie macchine quad core soffrirebbero?

Ad esempio, c'è comunque qualcosa da fare, se la CPU ha due core, quindi usare 20, se la CPU ha quattro core allora 40?

risposta

58

La risposta è che si tratta del limite superiore dell'intera operazione parallela, indipendentemente dal numero di core.

Quindi, anche se non si utilizza la CPU perché si sta aspettando su IO o su un blocco, non verranno eseguite altre attività in parallelo, ma solo il massimo specificato.

Per scoprire questo, ho scritto questo pezzo di codice di prova. C'è un blocco artificiale lì per stimolare il TPL ad usare più thread. Lo stesso accadrà quando il tuo codice è in attesa di IO o database.

class Program 
{ 
    static void Main(string[] args) 
    { 
     var locker = new Object(); 
     int count = 0; 
     Parallel.For 
      (0 
      , 1000 
      , new ParallelOptions { MaxDegreeOfParallelism = 2 } 
      , (i) => 
        { 
         Interlocked.Increment(ref count); 
         lock (locker) 
         { 
          Console.WriteLine("Number of active threads:" + count); 
          Thread.Sleep(10); 
         } 
         Interlocked.Decrement(ref count); 
        } 
      ); 
    } 
} 

Se non specificare MaxDegreeOfParallelism, la registrazione della console mostra che fino a circa 8 attività sono in esecuzione allo stesso tempo. Come questo:

Number of active threads:6 
Number of active threads:7 
Number of active threads:7 
Number of active threads:7 
Number of active threads:7 
Number of active threads:7 
Number of active threads:6 
Number of active threads:7 
Number of active threads:7 
Number of active threads:7 
Number of active threads:7 
Number of active threads:7 
Number of active threads:7 
Number of active threads:7 
Number of active threads:7 
Number of active threads:7 
Number of active threads:7 
Number of active threads:7 
Number of active threads:7 

Si parte inferiore, aumenta nel tempo e alla fine si sta cercando di eseguire 8 allo stesso tempo.

Se mi limito a qualche valore arbitrario (ad esempio 2), ottengo

Number of active threads:2 
Number of active threads:1 
Number of active threads:2 
Number of active threads:2 
Number of active threads:2 
Number of active threads:2 
Number of active threads:2 
Number of active threads:2 
Number of active threads:2 
Number of active threads:2 
Number of active threads:2 
Number of active threads:2 
Number of active threads:2 
Number of active threads:2 
Number of active threads:2 
Number of active threads:2 
Number of active threads:2 

Oh, e questo è su una macchina quadcore.

+0

La mia logica non ha alcuna attesa o alcun IO, semplicemente aggiorna SQL, sì SQL potrebbe avere il suo, ma soprattutto sto aspettando che l'SQL finisca. Qual è il numero massimo predefinito di thread attivi utilizzati? –

+0

Il valore predefinito è 2 per core, ma il TPL può sollevarlo se il codice non utilizza la CPU. La maggior parte dei database coinvolge una certa quantità di IO. –

+1

Se il mio computer a 6 core è molto carico, utilizza solo 1 o 2 thread. Se è leggermente caricato, sale a 12. È abbastanza intelligente da tenere conto del carico del sistema esistente. – Contango

-1

imposta numero di thread per eseguire in parallelo ...

+0

Ma prende in considerazione i nuclei? –

+0

in pratica che tipo di db stai usando? – SolidSnake

+0

stesso OS, stesso programma, stessi dati (Replicatori bascialmente), ma uno è una macchina di fascia alta con doppio quad core e due sono semplici macchine dual core, lo stesso programma recupera dati da altri server e memorizza i dati su SQL (un sacco di BLOB e immagini). –

1

Suona come il codice che si sta eseguendo in parallelo è deadlocking, il che significa che se non è possibile trovare e risolvere il problema che sta causando che, non dovresti parallelizzarlo affatto.

+0

-1, la domanda non è parallela o non parallela, è semplice che SQL esegua i propri calcoli ma troppe richieste parallele rendono il timeout del client, voglio eseguire meno operazioni. Deadlock non è un problema come macchina quad core con la stessa logica, lo stesso SQL funziona bene, non voglio continuare ad aumentare il timeout. –

+0

Hai provato ad aumentare il timeout e hai confermato che funziona? I problemi di concorrenza possono essere estremamente sottili e molte cose possono farli sparire e riapparire apparentemente a caso. Il fatto che abbia funzionato su una macchina diversa con più core non significa che non sia rotto, o che più core siano stati la cosa che ha aiutato. – jimrandomh

+0

L'aumento del timeout aiuta. Ma in qualche modo l'utilizzo della CPU è superiore al 50% su macchine di piccole dimensioni e su macchine di grandi dimensioni è inferiore al 5%, ora sono a un punto in cui ho bisogno di scoprire problemi di prestazioni e c'è qualcosa che posso fare per cambiare codice o fare solo bisogno aggiornare la CPU. –

13

Ad esempio, c'è comunque qualcosa da fare, se la CPU ha due core, quindi usare 20, se la CPU ha quattro core e 40?

Si può fare questo per rendere il parallelismo dipende dal numero di core della CPU:

var options = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount * 10 }; 
Parallel.ForEach(sourceCollection, options, sourceItem => 
{ 
    // do something 
}); 

Tuttavia, le nuove CPU tendono ad usare l'hyper-threading per simulare core in più. Quindi se hai un processore quad-core, allora lo Environment.ProcessorCount lo segnalerà come 8 core. Ho scoperto che se si imposta il parallelismo per rendere conto dei core simulati, in realtà rallenta altri thread come i thread dell'interfaccia utente.

Quindi anche se l'operazione terminerà un po 'più velocemente, un'interfaccia utente dell'applicazione potrebbe subire un ritardo significativo durante questo periodo. La divisione di "Environment.ProcessorCount" di 2 sembra raggiungere le stesse velocità di elaborazione mantenendo la CPU disponibile per i thread UI.