2011-02-04 7 views
13

AGGIORNAMENTO: Ho usato il threading per suddividere il loop nella quantità di kernel (8 nel mio caso) e il ciclo completo è andato avanti in meno di 1 secondo. Quindi il problema non è che l'Operazione non è più veloce con il threading. Perché Parralel Extension ha fallito in questo caso?Parallelo.Più veloce/lento come normale PerOne

Ciao a tutti. Voglio convertire il mio ForEach con Parrallel.Foreach. Il problema è che la parralelizzazione non ha praticamente alcun vantaggio per me.

originale:

foreach (Entities.Buchung buchung in buchungen) { 
    Int32 categoryID = manager.GetCategoryID(new Regelengine.Booking(buchung)); // Average 4ms 
    buchung.Category = categoryID.ToString(); 
} 

parallele:

System.Threading.Tasks.Parallel.ForEach(buchungen, buchung => { 
    Int32 categoryID = manager.GetCategoryID(new Regelengine.Booking(buchung)); 
    buchung.Category = categoryID.ToString(); 
}); 

Risultati:

--------------------------- 
Stopwatched Results for 1550 entries in the List: 
--------------------------- 
Parallel.Foreach 00:00:07.6599066 
Average Foreach: 00:00:07.9791303 

Forse il problema è che l'azione reale nel circuito è così breve? Ma nessuno può dirmi che parallelizzare le operazioni 1550 su un Intel I7 non salverà in alcun momento.

+0

Probabilmente c'è un blocco in quella cosa di "Regelengine". – leppie

+2

La domanda è: il metodo all'interno dell'istruzione trae profitto dal parallelismo? La prossima cosa che non so è cosa fa GetCategoryID. Esiste una chiamata al database che potrebbe essere il collo di bottiglia e impedire al codice di utilizzare il multithreading. – sprinter252

+2

Cosa succede nel metodo 'manager.GetCategoryID'? Cosa succede nel ctor 'new Regelengine.Booking'? – AakashM

risposta

9

C'è solo una risorsa che è possibile sfruttare utilizzando Parallel.Per: cicli della CPU. Quando hai N core, puoi teoricamente accelerare il tuo codice di un fattore N. Ciò che è tuttavia necessario è che in realtà sono i cicli della CPU che è il vincolo del tuo codice. Che non è spesso il caso a meno che non si esegua codice computazionalmente costoso. Altri vincoli sono la velocità del disco rigido, la connessione di rete, un server dbase, in alcuni casi la larghezza di banda del bus di memoria. Ne hai solo uno, Parallel. Per non poterti dare magicamente un altro disco.

Verificare se Parallel.Per accelerare il codice è piuttosto semplice. Basta eseguire il codice senza parallelizzare e osservare il carico della CPU in Taskmgr.exe o Perfmon. Se un core non è in esecuzione al 100%, il tuo codice non è vincolato all'elaborazione. Se funziona a, diciamo, il 10%, allora puoi solo sperare di farcela impiegare il 90% delle volte, indipendentemente dal numero di core che hai. Che otterrete sovrapponendo il tempo di attesa I/O con il tempo di elaborazione, due thread otterranno questo risultato.

5

domande che si dovrebbero prendere in considerazione in questo sono:

  • Qual è il sovraccarico di girare un thread?
  • Qual è il sovraccarico del mio filo di sicurezza (serrature)?
  • Dove sono i colli di bottiglia attuali e saranno multithreading davvero aiutare?

L'ultimo è il tuo più grande considerazione qui. Ad esempio, se stai eseguendo il maxing del tuo canale I/O, tutti i thread nel mondo non eseguiranno lo squat. Quindi il tuo compito è legato alla CPU o legato all'I/O?

+0

La creazione del thread non dovrebbe essere abbastanza costosa per creare questo effetto. E dire serrature con dire dove non è utile. –

+0

Grazie per la tua risposta, ma ho usato le normali discussioni ora per suddividere il ciclo manualmente e tutto è andato in men che non si dica. Quindi il problema non è nel threading dei suoi anni, ma in ForeachLoop? – Steav

1

penso che tu abbia ragione, lo fa apparire un po 'troppo breve per essere vale la pena utilizzare foreach parallelo. Uso la foreach parallela solo quando so che sta per accadere qualcosa di importante nel foreach che richiederà del tempo, o potrebbe richiedere del tempo, come una connessione al database o se sto inviando molti dati a un servizio web. Se si tratta solo di elaborare le informazioni sul server, come se si trattasse solo di ottenere gli ID da una raccolta che è già stata caricata in memoria, non ne verrebbe veramente la pena.

0

Prima di tutto, 1550 non è molto. Ad esempio, l'ordinamento di un array di questi molti elementi sarà in genere più veloce se eseguito in sequenza rispetto a quando eseguito in parallelo. Tutto dipende dall'operazione.

In secondo luogo, cosa GetCategoryID fare? Usa le serrature? Del resto, è il costruttore Regelengine.Booking?

Il tempo di funzionamento totale di 7 secondi indica che l'operazione è sufficientemente lenta da consentire a di beneficiare della parallela. D'altra parte, il tuo codice sembra indicare che in realtà non è in corso molta elaborazione. Probabilmente stai caricando i dati dal disco o da un database. In entrambi i casi, questo è un collo di bottiglia a cui la parallelizzazione non può fare (quasi) nulla contro. L'elaborazione simultanea rende il tuo codice più veloce solo se è legato all'elaborazione.

Ma non hai dato abbastanza informazioni per determinarlo.

1

Il parallelismo non sarà più veloce se non si dispone di core disponibili da utilizzare.Quindi quando vedo un codice come questo il mio primo pensiero è che tu abbia altri thread in esecuzione.

Potrebbe anche essere il carico di lavoro. La logica di sincronizzazione non è libera e ogni iterazione non fa molto. Prendi in considerazione gli altri sovraccarichi di Parallel.ForEach per le opzioni che puoi modificare.

Prova anche a utilizzare Parallel.Per. Non puoi leggere da un oggetto IEnumerable in modo parallelo, ma puoi farlo da un IList usando gli indici.