2012-06-01 18 views
5

Forse non ho capito bene ... tutta la questione di classe parallela :(Utilizzare System.Threading.Tasks.Parallel creare un nuovo thread nel pool di thread?

Ma da quello che sto leggendo ora, capisco che quando uso il parallelo in realtà ho mobilitare tutti i fili che esiste nel ThreadPool per un certo compito/missione

per esempio:..

var arrayStrings = new string[1000]; 
    Parallel.ForEach<string>(arrayStrings, someString => 
    { 
     DoSomething(someString); 
    }); 

Così il Parallel.ForEach in questo caso è la mobilitazione di tutti i thread che esiste nel ThreadPool per il 'DoSomething' compito/missione

Ma la chiamata Parallel.ForEach creerà un nuovo thread?

È chiaro che non ci saranno 1000 nuovi thread. Ma supponiamo che ci siano 1000 nuovi thread, alcuni casi in cui threadPool rilascia tutto il thread che tiene così, in questo caso ... il Parallel.ForEach creerà un nuovo thread?

+0

['Parallel.ForEach'] (http://msdn.microsoft.com/en-us/library/system.threading.tasks.parallel.foreach.aspx) -" Esegue un foreach (per ciascuno in Visual Basic) operazione in cui le iterazioni ** possono ** essere eseguite in parallelo. " –

risposta

10

Risposta breve: Parallel.ForEach() non "mobilita tutti i thread". E qualsiasi operazione che pianifica alcuni lavori su ThreadPool (che lo fa Parallel.ForEach()) può causare la creazione di un nuovo thread nel pool.

Risposta lunga: Per capire questo correttamente, è necessario sapere come tre livelli di lavoro di astrazione: Parallel.ForEach(), TaskScheduler e ThreadPool:

  1. Parallel.ForEach() (e Parallel.For()) programmare il loro lavoro su un TaskScheduler. Se non si specifica esplicitamente uno scheduler, verrà utilizzato the current one.

    Parallel.ForEach() suddivide il lavoro tra diversi Task s. Ogni Task elaborerà una parte della sequenza di input e, al termine, richiederà un'altra parte se ne è disponibile una e così via.

    Quantivengono creati da Parallel.ForEach()? Tanto quanto lo TaskScheduler lascerà correre. Il modo in cui questo viene fatto è che ogni Task prima accoda una copia di se stesso quando inizia l'esecuzione (a meno che così facendo violerebbe lo MaxDegreeOfParallelism, se lo si imposta). In questo modo, il livello di concorrenza effettivo è pari a TaskScheduler.

    Inoltre, il primo Task sarà effettivamente eseguito sul thread corrente, se il TaskScheduler lo supporta (questo viene fatto utilizzando RunSynchronously()).

  2. The default TaskScheduler semplicemente accoda ogni Task alla coda ThreadPool. (In realtà, è più complicato se si avvia uno Task da un altro Task, ma non è rilevante qui.) Altri TaskScheduler s possono fare cose completamente diverse e alcuni di essi (come TaskScheduler.FromCurrentSynchronizationContext()) sono completamente inadatti per l'uso con Parallel.ForEach().

  3. Il ThreadPool utilizza un algoritmo piuttosto complesso per decidere esattamente quanti thread devono essere in esecuzione in un dato momento. Ma la cosa più importante qui è che la pianificazione di un nuovo oggetto di lavoro può causare la creazione di un nuovo thread (anche se non necessariamente immediatamente). E poiché con Parallel.ForEach(), c'è sempre qualche elemento in coda da eseguire, è completamente all'algoritmo interno di ThreadPool decidere il numero di thread.

Mettere insieme, è praticamente impossibile decidere quanti thread verrà utilizzata da un Parallel.ForEach(), perché dipende da molte variabili. Entrambi gli estremi sono possibili: che il ciclo verrà eseguito in modo sincrono sul thread corrente e che ogni elemento verrà eseguito sul proprio thread appena creato.

Ma generalmente, dovrebbe essere vicino all'ottimizzazione ottimale e probabilmente non devi preoccuparti di tutti quei dettagli.

1

Parallel.Foreach non crea nuovi thread né "mobilizza tutti i thread". Usa un numero limitato di thread dal threadpool e invia loro delle attività per l'esecuzione parallela. Nell'attuale implementazione l'impostazione predefinita prevede l'uso di un thread per core.

+1

Semplicemente non è vero. Se il codice all'interno di 'Parallel.ForEach()' blocca o gira per un lungo periodo, verranno utilizzati più thread del numero di core. – svick

0

Parallelamente non gestisce affatto i thread - pianifica le ATTIVITÀ per il framework delle attività. Quindi ha uno scheduler e lo scheduler predefinito va al threadpool. Questo cercherà di trovare un numero goo di thread (meglio tra 4.5 e 4.0) e Threadpool potrebbe far ruotare lentamente i nuovi thread.

Ma questo non è un functoin di Parallel.ForEach;)

il Parallel.ForEach creerà alcun nuovo thread ???

Non lo farà mai. Come ho detto, ha 1000 punti di sicurezza, quindi mette in coda 10.000 compiti, Punto. L'utilità di pianificazione delle attività farà ciò che è programmato per fare ((è possibile sostituirlo). In genere, di default, sì, lentamente nuovi thread verranno generati entro IN RAGIONE

+0

'Parallel.ForEach()' su una raccolta di * n * elementi in genere non creeranno * n * 'Task's, che potrebbe essere troppo inefficiente. Partiziona la raccolta di sorgenti e crea solo tanti 'Task' come' TaskScheduler' gli consente di eseguire. – svick

1

Penso che tu abbia questo verso il tondo sbagliato. da PATTERNS OF PARALLEL PROGRAMMING vedrai che Parallel.ForEach è lo zucchero solo molto sintattico.

il Parallel.ForEach è in gran parte riassunta in qualcosa di simile,

for (int p = 0; p < arrayStrings.Count(); p++) 
{ 
    ThreadPool.QueueUserWorkItem(DoSomething(arrayStrings[p]); 
} 

il ThreadPool si occupa della pianificazione. ci sono alcuni articoli eccellenti su come lo scheduler di ThreadPool si comporta in una certa misura Se sei interessato, ma questo non ha nulla a che fare con TPL.

+1

'new Thread()' creerà sempre un nuovo thread, non ne userà uno dal threadpool.Il codice che hai postato crea sempre tanti thread quanti sono gli elementi nella collezione. Questo non rappresenta in alcun modo Parallel.ForEach. –

+0

@ AllonGuralnek sei corretto, aggiornato. –

+1

'Parallel.ForEach()' non è costruito su 'ThreadPool', è costruito su' TaskScheduler'. Inoltre, è più intelligente sul codice in ogni 'Task', in modo che non ci sia un' Task' per elemento. Un'altra cosa è che il tuo codice non bloccherebbe, ma 'Parallel.ForEach()' lo fa. – svick

Problemi correlati