Thread pool
# Thread pool

Un thread pool in programmazione indica un gestore software di thread utilizzato per ottimizzare e semplificare l'utilizzo dei thread all'interno di un programma.

## Funzionamento generale

Durante la stesura di un programma è possibile, con diversi metodi, sottomettere dei task (o compiti) da eseguire al thread pool. Sarà compito del thread pool affidare il task ad un thread. Generalmente i thread pool sono dotati di una coda interna di task in attesa e di un certo numero di thread con cui eseguirli. A seconda dell'implementazione del thread pool vengono utilizzate regole diverse per decidere quale task eseguire per primo, quanti thread attivi utilizzare e quanti thread lasciare in attesa quando la coda dei task è vuota.

Un concetto ricorrente nei thread pool è il riutilizzo dei thread: un thread viene usato più volte per diversi task durante il suo ciclo di vita. Questo diminuisce l'overhead dovuto alla creazione dei thread e incrementa le prestazioni del programma che sfrutta il thread pool. Il riutilizzo dei thread non è una regola, ma è uno dei principali motivi che portano un programmatore a utilizzare un thread pool nei suoi applicativi.

## Implementazione e funzionamento

Una implementazione di thread pool è composta di solito da una coda di task e da un insieme di thread, entrambi inizialmente vuoti. I parametri di funzionamento tipici sono i seguenti:

* la lunghezza della coda di task (può essere virtualmente infinita);
* il numero di thread che rimangono in vita in assenza di task;
* il numero massimo di thread che possono essere creati (può essere virtualmente infinito).

Una volta che il thread pool è stato inizializzato, è possibile richiedere che vengano creati subito i thread minimi, cioè quelli che rimarrebbero in vita anche in assenza di task. Spesso viene sfruttata questa funzione se si prevede un utilizzo intensivo del thread pool e si vuole una certa reattività nell'esecuzione dei task. A questo punto è possibile chiedere al thread pool di eseguire dei task: si possono aggiungere alla coda interna un qualsiasi numero di compiti indipendenti fra di loro, senza interrompere il flusso principale del programma che sfrutta il thread pool. Se la coda di task è infinita, il task viene sempre accettato, in caso contrario potrebbe venir rifiutato se la coda fosse piena. Ogniqualvolta il thread pool accetta un task, controlla se ci sono dei thread liberi in attesa e in tal caso assegna ad uno di essi il task. Se non ci sono thread liberi controlla se è possibile crearne uno nuovo: se è stato raggiunto il numero massimo di thread, il task viene messo in coda, altrimenti ne viene creato uno nuovo e gli viene assegnato il task. In alcune implementazioni la coda dei task può essere a priorità o non esistere (cioè avere lunghezza 0). Nel primo caso l'estrazione di un task dalla coda è dipendente dalla sua priorità, nel secondo caso il task viene accettato solo se può essere mandato in esecuzione immediatamente. Quando un thread ha finito di eseguire un task passa al prossimo compito in coda, se presente. Se non ci sono task in attesa il thread stesso controlla se è in esubero: se ci sono più thread attivi di quelli minimi (che possono rimanere in attesa di compiti) esso termina e conclude il suo ciclo di vita, altrimenti si mette in attesa. Un thread pool generalmente ha anche un metodo per aspettare la conclusione dei task assegnati o per chiudere forzatamente tutti i thread che sono ancora in vita scartando i task in coda.

Implementazioni differenti potrebbero prevedere comportamenti diversi, ma lo schema generico è quello presentato finora.

## Vantaggi

Utilizzare un thread pool nativo o implementato in una particolare architettura comporta un incremento di prestazioni da parte delle applicazioni che lo sfruttano: i thread pool ottimizzano l'utilizzo della memoria e del processore, diminuendo l'overhead di gestione dei thread. È possibile comunque adeguare il thread pool alle proprie esigenze, nel caso i parametri standard non siano soddisfacenti. Oltretutto la parallelizzazione di alcune operazioni porta ad un'ottimizzazione delle risorse e ad un incremento di velocità nello svolgimento dei compiti, anche se introduce altri tipi di problemi come l'accesso esclusivo a risorse condivise (problema di race condition). Un thread pool permette di snellire il codice ed evitare di preoccuparsi della creazione e della terminazione dei thread, in special modo quando non se ne conosce la quantità.

## Architetture che utilizzano i thread pool

I thread pool sono utilizzati in quasi tutte le applicazioni server, in cui c'è l'esigenza di trattare più richieste contemporanee da parte di un numero imprecisato di client. Molte altre applicazioni però hanno bisogno che ogni task venga eseguito istantaneamente o che si abbia un controllo maggiore sul thread che lo esegue: in questo caso il thread pool non è la scelta migliore.

## Linguaggi che implementano i thread pool

* Java.
* Tutti i linguaggi che sfruttano il .NET Framework.

### Esempi

Di seguito sono riportati alcuni esempi di utilizzo dei thread pool nei principali linguaggi di programmazione che li supportano nativamente.

