Potenza e controllo con le Parallel Libraries Twitter: @raffaeler Email: [email protected] Articoli e...
-
Upload
ginevra-merlo -
Category
Documents
-
view
215 -
download
3
Transcript of Potenza e controllo con le Parallel Libraries Twitter: @raffaeler Email: [email protected] Articoli e...
![Page 1: Potenza e controllo con le Parallel Libraries Twitter: @raffaeler Email: malta@vevy.com Articoli e codice: Blog: .](https://reader036.fdocument.pub/reader036/viewer/2022070312/5542eb64497959361e8cd670/html5/thumbnails/1.jpg)
Potenza e controllocon le Parallel Libraries
Raffaele Rialdi
Twitter: @raffaeler
Email: [email protected]
Articoli e codice: http://www.iamraf.net
Blog: http://blogs.ugidotnet.org/raffaele
Profilo MVP: https://mvp.support.microsoft.com/profile/raffaele
![Page 2: Potenza e controllo con le Parallel Libraries Twitter: @raffaeler Email: malta@vevy.com Articoli e codice: Blog: .](https://reader036.fdocument.pub/reader036/viewer/2022070312/5542eb64497959361e8cd670/html5/thumbnails/2.jpg)
Massima performance possibile• La legge di Amdahls dice che si può ottenere al massimo un guadagno di
– 1/[percentuale spesa nell'esecuzione sequenziale]
• Tutto quindi dipende dalla suddivisione in task– In pratica ogni task è l'unità minima di lavoro sequenziale
• In assenza di I/O il mapping 1 task per ogni core permette usare al massimo le cpu
• Numero ottimale di thread = core / percentuale media di utilizzo per task– Se un task impegna la cpu al 50%– Se ho a disposizione 4 core– Il numero di thread ottimale è 8
![Page 3: Potenza e controllo con le Parallel Libraries Twitter: @raffaeler Email: malta@vevy.com Articoli e codice: Blog: .](https://reader036.fdocument.pub/reader036/viewer/2022070312/5542eb64497959361e8cd670/html5/thumbnails/3.jpg)
Il Parallel Computing firmato Microsoft
Managed
Query PLinq
Data Partitioning
Standard Query Operators
Data Merging
Algoritmi
TPL(Task Parallel
Library)
Strutture dati di coordinazione
Nativo Concurrency Runtime
PPL(Parallel Patterns
Library)
Agents Library
![Page 4: Potenza e controllo con le Parallel Libraries Twitter: @raffaeler Email: malta@vevy.com Articoli e codice: Blog: .](https://reader036.fdocument.pub/reader036/viewer/2022070312/5542eb64497959361e8cd670/html5/thumbnails/4.jpg)
I Task
• Disaccoppia il concetto di esecuzione dal thread– Il Task può essere mappato su Thread o su Fiber– Un Thread può eseguire più Task
• Ogni task è esattamente un'istanza della classe Task• Sono in System.Threading.Tasks (mscorlib)
• I delegate usati da Task– Se non tornano risultati: Action o Action<object>– Se tornano risultati: Func<T> o Func<object, T>
• La proprietà Result fornisce accesso al risultato
• Espone le proprietà ID e Status• Espone i metodi WaitAny, WaitAll
![Page 5: Potenza e controllo con le Parallel Libraries Twitter: @raffaeler Email: malta@vevy.com Articoli e codice: Blog: .](https://reader036.fdocument.pub/reader036/viewer/2022070312/5542eb64497959361e8cd670/html5/thumbnails/5.jpg)
Lo scheduler
• Usano un 'managed user mode scheduler'– Integrato all'interno del ThreadPool standard
• Scalabilità automatica– Lo scheduler a runtime decide il numero di core da
utilizzare– Il developer ha comunque modo di limitarli
• È possibile fornire un custom Scheduler• È possibile avviare un task nel contesto del thread
corrente (sincrono)
![Page 6: Potenza e controllo con le Parallel Libraries Twitter: @raffaeler Email: malta@vevy.com Articoli e codice: Blog: .](https://reader036.fdocument.pub/reader036/viewer/2022070312/5542eb64497959361e8cd670/html5/thumbnails/6.jpg)
Taskusing(ManualResetEvent mre1 = new ManualResetEvent(false))using(ManualResetEvent mre2 = new ManualResetEvent(false))using(ManualResetEvent mre3 = new ManualResetEvent(false)){
ThreadPool.QueueUserWorkItem(delegate { A(); mre1.Set(); } );ThreadPool.QueueUserWorkItem(delegate { B(); mre2.Set(); } );ThreadPool.QueueUserWorkItem(delegate { C(); mre3.Set(); } );
WaitHandle.WaitAll(new WaitHandle[]{mre1, mre2, mre3});}
Task t1 = Task.Factory.StartNew(delegate { A(); });Task t2 = Task.Factory.StartNew(delegate { B(); });Task t3 = Task.Factory.StartNew(delegate { C(); });
Task.WaitAll(t1, t2, t3);
Task t1 = Task.Factory.StartNew(() => A());Task t2 = Task.Factory.StartNew(() => B());Task t3 = Task.Factory.StartNew(() => C());
Task.WaitAll(t1, t2, t3);
==
![Page 7: Potenza e controllo con le Parallel Libraries Twitter: @raffaeler Email: malta@vevy.com Articoli e codice: Blog: .](https://reader036.fdocument.pub/reader036/viewer/2022070312/5542eb64497959361e8cd670/html5/thumbnails/7.jpg)
Continuations
• Permettono di decidere l'ordine temporale di esecuzione di Task e Task<T>– Utile quando una esecuzione necessita il risultato di una
esecuzione precedente– Non viene garantito che il thread di esecuzione sia sempre
lo stesso
var res = Task<int>.Factory.StartNew(() => A(10)).ContinueWith<int>(a => B(a.Result)).ContinueWith<int>(b => C(b.Result));
![Page 8: Potenza e controllo con le Parallel Libraries Twitter: @raffaeler Email: malta@vevy.com Articoli e codice: Blog: .](https://reader036.fdocument.pub/reader036/viewer/2022070312/5542eb64497959361e8cd670/html5/thumbnails/8.jpg)
AggregateException
• L'esecuzione parallela può implicare eccezioni contemporanee• La TPL aggrega le eccezioni in AggregateException
– Questo significa che la migrazione di codice esistente non è trasparente (le catch devono essere rivedute)
– L'esecuzione non continua e riporta solo le eccezioni contemporanee– La collection InnerExceptions contiene le eccezioni con lo Stack Trace
try{
Task.WaitAll(t1, t2);}catch(AggregateException err){
foreach(var e in err.InnerExceptions){
Console.WriteLine("Catched! " + e.Message);}throw err.Flatten();
}
try{
Task.WaitAll(t1, t2, t3);}catch(AggregateException err){
err.Handle(e =>{
Console.WriteLine("Catched {0}: {1}",e.GetType().FullName, e.Message);
return true; // handled});
}
![Page 9: Potenza e controllo con le Parallel Libraries Twitter: @raffaeler Email: malta@vevy.com Articoli e codice: Blog: .](https://reader036.fdocument.pub/reader036/viewer/2022070312/5542eb64497959361e8cd670/html5/thumbnails/9.jpg)
Parallel.For, Parallel.ForEach, Parallel.Invoke
for (int i = 0; i < N; i++){
results[i] = Compute(i);}
Parallel.For(0, N, i =>{
results[i] = Compute(i);} );
foreach(MyClass c in data){
Compute(c);}
Parallel.ForEach(data, c =>{
Compute(c);} );
static void WalkTree<T>(Tree<T> tree, Action<T> func){
if (tree == null) return;WalkTree(tree.Left, func);WalkTree(tree.Right, func);func(tree.Data);
}
static void WalkTree<T>(Tree<T> tree, Action<T> func){
if (tree == null) return;Parallel.Invoke(
() => WalkTree(tree.Left, func) ,() => WalkTree(tree.Right, func) ,() => func(tree.Data) );
}
![Page 10: Potenza e controllo con le Parallel Libraries Twitter: @raffaeler Email: malta@vevy.com Articoli e codice: Blog: .](https://reader036.fdocument.pub/reader036/viewer/2022070312/5542eb64497959361e8cd670/html5/thumbnails/10.jpg)
Parallel.For - break e stop
• ParallelLoopState permette di invocare Break e Stop– Break permette un'interruzione 'soft'
• Le operazioni in esecuzione dal task da cui viene eseguito Break (o i task child) verranno completate
• LowestBreakIteration è il minimo indice al di sotto del quale tutti i risultati sono validi
– LowestBreakIteration è un nullable type
– Stop interrompe totalmente l'esecuzione• A fine loop LowestBreakIteration.HasValue è false
![Page 11: Potenza e controllo con le Parallel Libraries Twitter: @raffaeler Email: malta@vevy.com Articoli e codice: Blog: .](https://reader036.fdocument.pub/reader036/viewer/2022070312/5542eb64497959361e8cd670/html5/thumbnails/11.jpg)
Cancellation
• CancellationTokenSource e CancellationToken servono a informare i Task che devono interrompere le operazioni
• La segnalazione ad un Task parent viene propagata ad i Task Child per tutta la gerarchia
• Il Task deve essere collaborativo e controllare periodicamente la richiesta di annullamento
![Page 12: Potenza e controllo con le Parallel Libraries Twitter: @raffaeler Email: malta@vevy.com Articoli e codice: Blog: .](https://reader036.fdocument.pub/reader036/viewer/2022070312/5542eb64497959361e8cd670/html5/thumbnails/12.jpg)
PLINQPARALLEL LINQ
![Page 13: Potenza e controllo con le Parallel Libraries Twitter: @raffaeler Email: malta@vevy.com Articoli e codice: Blog: .](https://reader036.fdocument.pub/reader036/viewer/2022070312/5542eb64497959361e8cd670/html5/thumbnails/13.jpg)
PLinq
• Permette di eseguire query parallele le query verso oggetti e XML
• NON serve a parallelizzare Linq to SQL o l'entity framework– È comunque possibile eseguire query parallele sui risultati
ottenuti con queste tecnologie
• Il concetto base consiste nel "partizionare" porzioni di una query– Ogni thread calcola un pezzo e lo aggiunge al risultato
![Page 14: Potenza e controllo con le Parallel Libraries Twitter: @raffaeler Email: malta@vevy.com Articoli e codice: Blog: .](https://reader036.fdocument.pub/reader036/viewer/2022070312/5542eb64497959361e8cd670/html5/thumbnails/14.jpg)
PLinq
• ParallelEnumerable è la classe che contiene gli extension methods con le implementazioni parallele di Linq– Count, First, Last, Distinct, Join, Average, Aggregate, …
![Page 15: Potenza e controllo con le Parallel Libraries Twitter: @raffaeler Email: malta@vevy.com Articoli e codice: Blog: .](https://reader036.fdocument.pub/reader036/viewer/2022070312/5542eb64497959361e8cd670/html5/thumbnails/15.jpg)
Operatori specifici di PLinq• AsParallel
– Parallelizzare il resto della query, se possibile
• AsSequential– Il resto della query deve essere eseguita in modo sequenziale invece di parallelo
• AsOrdered, AsUnordered– La query deve rispettare / non rispettare l'ordine della sequenza sorgente
• WithCancellation– Si richiede di monitorare il flag di annullamento
• WithDegreeOfParallelism– Numero massimo di Core da usare nella query
• WithMergeOptions– Suggerimenti su come eseguire il merge dei risultati paralleli parziali
• WithExecutionMode– Per forzare l'esecuzione parallela anche quando verrebbe eseguita sequenzialmente dal runtime
• ForAll– Permette di fruire in modo parallelo il risultato senza necessità di eseguire il merge sul thread che ha avviato la
query
• Aggregate– Permette l'aggregazione parziale dei risultati mantenuti in partizioni specifiche al TLS
![Page 16: Potenza e controllo con le Parallel Libraries Twitter: @raffaeler Email: malta@vevy.com Articoli e codice: Blog: .](https://reader036.fdocument.pub/reader036/viewer/2022070312/5542eb64497959361e8cd670/html5/thumbnails/16.jpg)
Esecuzione parallela
• L'uso di AsParallel non implica che l'esecuzione avvenga in modo parallelo
• PLinq analizza la query e decide di parallelizzarla solo se la ritiene "safe"
• WithExecutionMode e WithDegreeOfParallelism sono molto utili per testare il guadagno al crescere dei core– In produzione è preferibile lasciare a PLinq la decisione del
numero di core da usare
![Page 17: Potenza e controllo con le Parallel Libraries Twitter: @raffaeler Email: malta@vevy.com Articoli e codice: Blog: .](https://reader036.fdocument.pub/reader036/viewer/2022070312/5542eb64497959361e8cd670/html5/thumbnails/17.jpg)
Query ordering in PLinq
• Le query parallele sono eseguite a pezzi in thread diversi– Ogni volta l'ordine del risultato può essere differente
Th
rea
d 3
Th
rea
d 2
Th
rea
d 1
Th
rea
d 4
3Risultato 2 1 4
linea temporale t
![Page 18: Potenza e controllo con le Parallel Libraries Twitter: @raffaeler Email: malta@vevy.com Articoli e codice: Blog: .](https://reader036.fdocument.pub/reader036/viewer/2022070312/5542eb64497959361e8cd670/html5/thumbnails/18.jpg)
Query ordering in PLinq• Possibilmente non fare affidamento sull'ordine del
risultato– I database fanno la stessa cosa
• Se è richiesto un risultato ordinato– Se possibile, ordinarlo dopo la query e non prima
– Diversamente specificare la clausola AsOrdered
– Oppure usare la clausola OrderBy
Array.Sort(a);var q = from x in a.AsParallel() ...
var q = from x in a.AsParallel() ...Array.Sort(q);
Array.Sort(a);var q = from x in a.AsParallel().AsOrdered() ...
Array.Sort(a);var q = from x in a.AsParallel().OrderBy(...) ...
![Page 19: Potenza e controllo con le Parallel Libraries Twitter: @raffaeler Email: malta@vevy.com Articoli e codice: Blog: .](https://reader036.fdocument.pub/reader036/viewer/2022070312/5542eb64497959361e8cd670/html5/thumbnails/19.jpg)
Cancellation
• Si usa WithCancellation• CancellationToken e CancellationTokenSource
funzionano in modo identico a quanto già visto nei Task
![Page 20: Potenza e controllo con le Parallel Libraries Twitter: @raffaeler Email: malta@vevy.com Articoli e codice: Blog: .](https://reader036.fdocument.pub/reader036/viewer/2022070312/5542eb64497959361e8cd670/html5/thumbnails/20.jpg)
COLLECTION PARALLELE
![Page 21: Potenza e controllo con le Parallel Libraries Twitter: @raffaeler Email: malta@vevy.com Articoli e codice: Blog: .](https://reader036.fdocument.pub/reader036/viewer/2022070312/5542eb64497959361e8cd670/html5/thumbnails/21.jpg)
Collection in PFXSystem.Collections.Concurrent
• PFX offre diverse collection di dati tra cui:– ConcurrentBag<T>
• Lista non ordinata di oggetti
– ConcurrentDictionary<TKey, TValue>• Dizionario
– BlockingCollection<T>• Ottimizzata per gli scenari Producer-Consumer• Implementa IEnumerable<T>, ICollection<T> e IDisposable
– ConcurrentQueue<T> (analoga a Queue<T>)• Una lista FIFO concorrente• bool TryDequeue(out T result) e bool TryPeek(out T result)
– ConcurrentStack<T> (analoga a Stack<T>)• Una list LIFO concorrente• bool TryPop(out T result) e bool TryPeek(out T result)
• In particolare le Queue sono fondamentali per smistare dei lavori su un numero fisso di worker thread
![Page 22: Potenza e controllo con le Parallel Libraries Twitter: @raffaeler Email: malta@vevy.com Articoli e codice: Blog: .](https://reader036.fdocument.pub/reader036/viewer/2022070312/5542eb64497959361e8cd670/html5/thumbnails/22.jpg)
Classi 'Slim'
• Sono classi 'leggere' cioè che non fanno uso di risorse native, con grande beneficio in termini di performance– ManualResetSlim– SemaphoreSlim– CountDownEvent (usa ManualResetSlim internamente)
• In sostanza non devono eseguire la transizione User‒Mode Kernel‒Mode
![Page 23: Potenza e controllo con le Parallel Libraries Twitter: @raffaeler Email: malta@vevy.com Articoli e codice: Blog: .](https://reader036.fdocument.pub/reader036/viewer/2022070312/5542eb64497959361e8cd670/html5/thumbnails/23.jpg)
TIPS & TRICKS
![Page 24: Potenza e controllo con le Parallel Libraries Twitter: @raffaeler Email: malta@vevy.com Articoli e codice: Blog: .](https://reader036.fdocument.pub/reader036/viewer/2022070312/5542eb64497959361e8cd670/html5/thumbnails/24.jpg)
Task lunghi o corti?
• TaskCreationOptions.LongRunning– usato per dire allo scheduler di incrementare il numero di
thread (es: i task sono impegnati in I/O)
• Se un task dura più di 500ms entra in gioco il meccanismo di "starvation detection"– è una strategia per evitare potenziali deadlock
• Difendersi dallo starvation:– Task più piccoli possibile– Custom scheduler– ThreadPool.SetMaxThreads(Environment.ProcessorCount)
![Page 25: Potenza e controllo con le Parallel Libraries Twitter: @raffaeler Email: malta@vevy.com Articoli e codice: Blog: .](https://reader036.fdocument.pub/reader036/viewer/2022070312/5542eb64497959361e8cd670/html5/thumbnails/25.jpg)
Parallelizzare: problemi e soluzioni
• Per la gran parte dei casi rendere parallelo è problematico (the free lunch ...)
• Problema 1: lo stato condiviso tra più thread è un freno alla scalabilità e frutto di errori da incubo
• Problema 2: molti algoritmi sono intrinsecamente seriali e la loro versione parallela (se esiste) spesso è radicalmente differente
• Problema 3: i tradizionali sistemi di unit testing sono totalmente inefficaci perché le modalità di esecuzione dipendono dall'hardware e da altri fattori
![Page 26: Potenza e controllo con le Parallel Libraries Twitter: @raffaeler Email: malta@vevy.com Articoli e codice: Blog: .](https://reader036.fdocument.pub/reader036/viewer/2022070312/5542eb64497959361e8cd670/html5/thumbnails/26.jpg)
PARALLEL PATTERNS
![Page 27: Potenza e controllo con le Parallel Libraries Twitter: @raffaeler Email: malta@vevy.com Articoli e codice: Blog: .](https://reader036.fdocument.pub/reader036/viewer/2022070312/5542eb64497959361e8cd670/html5/thumbnails/27.jpg)
Una linea guida
• Scomporre i problemi in piccoli task– La dimensione conta!– Se ogni 'task' è troppo piccolo, l'overhead di gestione del task
finisce per penalizzare la sua esecuzione
• Coordinare l'esecuzione dei task– Strettamente dipendente da come funziona l'algoritmo
• Condividere i dati necessari all'esecuzione– Minore dipendenza da dati condivisi implica maggiori
performance– La condivisione implica l'accesso in modo serializzato alla risorse
condivise– Alcune tecniche minimizzano le implicazioni di performance
![Page 28: Potenza e controllo con le Parallel Libraries Twitter: @raffaeler Email: malta@vevy.com Articoli e codice: Blog: .](https://reader036.fdocument.pub/reader036/viewer/2022070312/5542eb64497959361e8cd670/html5/thumbnails/28.jpg)
Parallel Loop Pattern
• È applicabile quando ogni step del loop non richiede i dati precedenti
• Strumenti:– Parallel.For– Parallel.ForEach– Parallel (PLinq)
![Page 29: Potenza e controllo con le Parallel Libraries Twitter: @raffaeler Email: malta@vevy.com Articoli e codice: Blog: .](https://reader036.fdocument.pub/reader036/viewer/2022070312/5542eb64497959361e8cd670/html5/thumbnails/29.jpg)
Parallel Task Pattern
• Si possono isolare delle unità di lavoro distinte e con dipendenze ben definite?
• Le dipendenze sono limitate?• Se si verificano queste condizioni è possibile risolvere
creando tanti task quante sono le unità di lavoro
• Strumenti:– Task, Task<…>
![Page 30: Potenza e controllo con le Parallel Libraries Twitter: @raffaeler Email: malta@vevy.com Articoli e codice: Blog: .](https://reader036.fdocument.pub/reader036/viewer/2022070312/5542eb64497959361e8cd670/html5/thumbnails/30.jpg)
Parallel Aggregation Pattern
• Esiste qualche forma di aggregazione sul risultato dei dati?
• Ogni step dell'elaborazione produce una parte del risultato?
• Se si verificano queste condizioni si usano gli strumenti di aggregazione di PLinq
• Strumenti:– PLinq
• (from x in sequence.AsParallel() select f(x) ).Sum();
![Page 31: Potenza e controllo con le Parallel Libraries Twitter: @raffaeler Email: malta@vevy.com Articoli e codice: Blog: .](https://reader036.fdocument.pub/reader036/viewer/2022070312/5542eb64497959361e8cd670/html5/thumbnails/31.jpg)
Futures Pattern / Task Graph Pattern
• L'ordine di esecuzione di ogni step di elaborazione dipende dal flusso dei dati?
• Si può immaginare il progresso dell'elaborazione con un grafo dipendente dai dati?
• Se si verificano queste condizioni, è opportuno usare le Continuations
• Strumenti:– Task e Continuations
![Page 32: Potenza e controllo con le Parallel Libraries Twitter: @raffaeler Email: malta@vevy.com Articoli e codice: Blog: .](https://reader036.fdocument.pub/reader036/viewer/2022070312/5542eb64497959361e8cd670/html5/thumbnails/32.jpg)
Dynamic Task Parallelism Pattern
• La suddivisione del problema in step è dinamica?• L'algoritmo prevede l'uso di strutture ricorsive
durante l'elaborazione (es: grafi)?
• Se si tratta di percorrere un grafo, la soluzione si può trovare in Parallel.Invoke e ForEach
• Strumenti:– Parallel.*
![Page 33: Potenza e controllo con le Parallel Libraries Twitter: @raffaeler Email: malta@vevy.com Articoli e codice: Blog: .](https://reader036.fdocument.pub/reader036/viewer/2022070312/5542eb64497959361e8cd670/html5/thumbnails/33.jpg)
Domande ?