Thread Injection e ThreadPool 4.0

by Marco 7. settembre 2010 21.36

Con il .Net Framework 4.0 molte modifiche sono state fatte al nuovo ThreadPool(le potete leggere in un mio precendente post), una di quelle più interessanti è quella sull’algoritmo di “thread injection”, ovvero come regolare il numero di thread attivi contemporaneamente dato un insieme di work item(work item di tipo “worker” ovvero di pura computazione/dispatch non di I/O il quale segue regole completamente diverse).
Fino ad oggi l’algoritmo di injection è stato regolato principalmente da due parametri fondamentali, l’utilizzo di CPU e il throughput(work item eseguiti nell’unità di tempo). Per farla semplice semplice diciamo che se il processore è scarico di lavoro, nuovi thread vengono “attivati”, succesivamente ne viene controllato l’effettivo aumento del throughput, in caso positivo nuovi thread possono essere aggiunti altrimenti il “tentativo” di migliorare le prestazioni è fallito e quindi i thread vengono “disattivati”(il bisogno di inserire il throughput come parametro oltre al consumo di CPU è dovuto al fatto che un basso utilizzo di processore non significa che il sistema è “sottoutilizzato”, magari sta semplicemente paginando e quindi inserire più thread peggiora la situazione dato l’aumento del consumo di memoria). Purtroppo questo algoritmo presenta comunque dei limiti dovuti al fatto che il throughput viene influenzato non solo dal numero di thread attivi, ma da molti altri fattori(si pensi ad esempio al tipo di work item, ne esistono di “lenti” e di “veloci”, ma ve ne sono molti altri, ricordiamoci che siamo in un ambiente in cui esistono altri processi altri thread e un sistema operativo preemptive).
Una delle nuove migliorie introdotte a questo algoritmo viene dalla teoria del controllo dei sistemi e si tratta dell’algoritmo di Hill Climbing (HC). Questo algoritmo effettua un “auto tuning” ad intervalli brevi controllando il numero di thread e il throughput, tuttavia questo algoritmo è soggetto ad errori dovuti ai “rumori”(disturbi dell’ambiente in cui il threadPool gira, altri processi,altri thread, sincronizzazione, SO etc…) che rendono il “tuning” di breve termine poco “credibile”. Per togliere i rumori dall’analisi viene utilizzata una tenica conosciuta nella “teoria dei segnali”, dove praticamente un segnale conosciuto viene aggiunto ad un’altro, questo permette di capire come il rumore incide sul segnale di uscita. Nel ThreadPool fate conto che il segnale di ingresso siano il numero thread più il nostro segnale conosciuto e che il segnale di uscita sia il throughput più il nostro segnale introdotto(il tutto “distorto” dal rumore). Queste tecniche vengono chiamate ad esempio “band pass filter” o “match filter” e servono per estrarre onde da altre onde(il ThreadPool utilizza una trasformata di Fourier discreta).

Questo algoritmo non è sicuramente “perfetto”, ma il team sostiene che funziona molto bene per “work item” corti dai 10ms ai 250ms.

A parte la “palla” teorica dovrebbe essere chiaro che scrivere un threadPool non è una cosa tanto facile, nella mia esperienza l’ho sempre usato e sempre lo userò quando avrò bisogno di eseguire un “lavoro” computazionale relativamente corto(se stiamo ad esempio in wait su una coda consumer/producer rubare un thread al threadPool non è il massimo data la natura “lunga” dell’attività, se lo fate con un Task delle TPL ricordatevi di usare il flag TaskCreationOptions.LongRunning che non va ad utilizzare il pool, ma crea un thread ad-hoc). Per concludere vi ricordo che le Task Parallel Library(e di conseguenza tutto quello costruito sopra come ad esempio PLINQ)  si avvalgono del nuovo ThreadPool per eseguire i Task(a parte nel caso di utilizzo del flag TaskCreationOptions.LongRunning come ho già spiegato).

Vota questo post per primo

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: ,

.Net | Concurrent Programming | Multithreading

Disclaimer
Le opinioni espresse in questo blog sono mie opinioni personali.

© Copyright 2012 Knowledge.CreateAsync()