2012-01-19 15 views
20

Oggi ho provato a fare qualche ottimizzazione sull'istruzione foreach, che funziona su XDocument.Perché non Parallel.ForEach esegue più thread?

Prima di ottimizzazione:

foreach (XElement elem in xDoc.Descendants("APSEvent").ToList()) 
{ 
    //some operations 
} 

Dopo l'ottimizzazione:

Parallel.ForEach(xDoc.Descendants("APSEvent").ToList(), elem => 
{ 
    //same operations 
}); 

ho visto che .NET in Parallel.ForEach(...) ha aperto solo un thread! Di conseguenza, il periodo di Parallel era più grande dello standard foreach.

Per quale motivo .NET ha aperto solo 1 thread? A causa del blocco del file? Grazie

+10

Quanti core o processori logici avete nel vostro computer? Quanti elementi ci sono nella lista? –

+0

Non riesco a vedere nessuna relazione tra il titolo e la domanda. –

+0

Christian.K, ho un server con processore Xeon e RAM da 8 GB (Dell PowerEdge R210) con sistema operativo MS Server2008. Penso che, non dipendendo da quanti elementi ho nel documento XML, penso che la penalità di tempo sia dovuta al blocco dei file. – zzfima

risposta

14

E 'di design che Parallel.ForEach può utilizzare un minor numero di thread di richiesta per ottenere prestazioni migliori. Secondo MSDN [link]:

Per impostazione predefinita, i metodi e Parallel.ForEach Parallel.For può utilizzare un numero variabile di compiti. Ecco perché, per esempio, la classe ParallelOptions ha una proprietà MaxDegreeOfParallelism invece di una proprietà "MinDegreeOfParallelism". L'idea è che il sistema possa utilizzare meno thread di quanto richiesto per elaborare un ciclo.

Il pool di thread .NET si adatta in modo dinamico ai carichi di lavoro in evoluzione consentendo al numero di thread di lavoro per le attività parallele di cambiare nel tempo. In fase di esecuzione, il sistema osserva se l'aumento del numero di thread migliora o riduce il throughput complessivo e regola di conseguenza il numero di thread di lavoro.

0

Sì, esattamente, Document.Load(...)locks the file e grazie a risorsa contesa tra i thread, TPL è in grado di utilizzare la potenza di più thread. Prova a caricare l'XML in un Stream e quindi usa Parallel.For(...).

+6

Questo spiegherebbe solo perché solo un thread _makes progress_, non perché solo un thread è _created_ - come afferma l'OP. 'Parallel.ForEach' non può (sensibilmente) avere alcuna conoscenza della collezione che sta iterando (solo" vede "un' List ' essere passato dentro ed è irragionevole supporre che abbia qualche implementazione speciale per quello). Inoltre, 'ToList' fondamentalmente recupera tutti gli elementi con entusiasmo, quindi il blocco (e il fatto che sia letto da un file) non dovrebbe fare alcuna differenza qui. –

-1

Ti capita di avere un singolo processore? In questo caso, il TPL potrebbe limitare il numero di thread a uno. La stessa cosa potrebbe accadere se la collezione è molto piccola. Prova una collezione più grande. Vedere this answer per ulteriori dettagli su come viene determinato il grado di parallelismo.

+2

Scherzo di una risposta. Probabilmente appropriato come commento. – Mukus

1

uso in questo modo:

int ParallelThreads = 10; 
Parallel.ForEach(xDoc.Descendants("APSEvent").ToList(), new ParallelOptions() { MaxDegreeOfParallelism = ParallelThreads }, (myXDOC, i, j) => 
{ 
//do whatever you want here 
}); 
+0

Basta notare che MaxDegreeOfParallelism imposta la quantità massima di thread, non il minimo. Pertanto, utile quando si desidera limitare o ridurre la quantità di thread/core utilizzati. – coloboxp

1

Dalla descrizione del problema, non c'è nulla che spieghi perché il TPL non stia generando più thread.

Non c'è alcuna prova nella domanda che sia anche il problema. Questo può essere risolto abbastanza facilmente: puoi inserire l'id del thread, prima di entrare nel ciclo, e come prima cosa fai nel loop.

Se è sempre lo stesso numero, è il TPL che non riesce a generare i thread. Dovresti quindi provare diverse versioni del tuo codice e quale modifica attiva la TPL per serializzare tutto. Una ragione potrebbe essere se ci sono un piccolo numero di elementi nella tua lista.La TPL partiziona la tua raccolta e, se hai solo pochi elementi, potresti finire con un solo batch. Questo comportamento è configurabile a proposito.

Potrebbe essere che inavvertitamente si fa il blocco del ciclo, quindi vedrete molti numeri diversi, ma nessuna accelerazione. Quindi, semplifica il codice fino a quando il problema non scompare.