Multithreading in Silverlight 2.0

di Cristian Civera, in Silverlight 2.0,

A metà ottobre 2008 Microsoft ha rilasciato ufficialmente Silverlight 2.0 arrivando per la prima volta a competere fortemente nel mondo client e delle applicazioni web come controparte principalmente di Adobe Flash. Per chi sviluppa già su piattaforma e tecnologia Microsoft sa che questa nuova tecnologia è una manna perché porta la potenza di .NET (performance, versatilità dei linguaggi e sicurezza del codice) anche sul client.

Si può definire Silverlight come uno sottoinsieme delle BCL (le classi basi di .NET) e di Windows Presentation Foundation, perciò chi già mastica queste tecnologie si troverà a suo agio e molti concetti di questo articolo saranno familiari. Tuttavia vi sono alcuni aspetti nuovi che vanno affrontanti se si vuole scrivere un'applicazione in Silverlight. Questo perché non si può fare diversamente: Microsoft obbliga a scrivere bene un'applicazione. I motivi sono principalmente la necessità di risparmiare sui membri disponibili nelle classi e rendere la dimensione del plugin il più piccolo possibile, e a parere dell'autore dell'articolo, favorire la fama di un nuovo plugin che nasce da zero; se le applicazioni funzionano male è il plugin che sfigura, non lo sviluppatore.

Thread principale

Qualsiasi applicazione risiede quindi in un plugin ospitato all'interno del browser e qualsiasi animazione, interazione con l'utente, evento o il semplice disegno dell'interfaccia coinvolgono delle operazioni che vengono eseguite in un unico thread, solitamente identificato come thread UI. Un thread è una suddivisione di un processo, quest'ultimo può contenere più di un thread ognuno dei quali compie un task in modo più o meno concorrente all'altro (dipende dal sistema operativo, dalla CPU e dalle risorse disponibili).

Il thread UI di Silverlight è il medesimo che usa il browser e tutti gli altri elementi gestiti nella pagina, di conseguenza ogni qual volta che, ad esempio, intercettiamo il click del pulsante, l'operazione/delegate che associamo a tale evento viene eseguita su questo thread. Se questa impiega molto tempo, il thread e le risorse che il sistema operativo alloca ad esso non sono disponibili andando così ad impedire che altri elementi dell'interfaccia presente nel browser possano reagire: le interazioni dell'utente non rispondono, la grafica non si aggiorna e l'intero browser sembra bloccato.

Questa è una delle principali problematiche da prendere in considerazione fin dall'inizio della scrittura dell'applicazione e va perciò valutato se ogni riga di codice che si scriva possa essere ragionevolmente performante da essere eseguita sul thread UI.

Proseguendo il viaggio sempre sul thread principale, per gestire l'intero ciclo di vita di un'applicazione in Silverlight è presente una coda di operazioni che vengono "consumate" appena inserite in coda, in un ordine FIFO (First In First Out), eventualmente con una priorità di esecuzione. Questa coda è rappresentata dalla classeDispatcher (System.Windows.Threading) ed ogni qual volta che si fa scattare un evento viene aggiunta una DispatcherOperation e, non appena possibile, processata. Tutto passa di qua, anche le operazioni di disegno dell'interfaccia o le Storyboard di animazione che lo sviluppatore non gestisce direttamente.

Eseguire operazioni ad intervalli

Non è raro in un'applicazione eseguire operazioni ad intervalli regolari, per aggiornare delle informazioni, per eseguire particolari animazioni o anche semplicemente per mostrare un orologio. A tale scopo è presente la classe DispatcherTimer il cui utilizzo è piuttosto semplice: si imposta l'intervallo con Interval e si avvia i timer con Start:

void startTimer_Click(object sender, RoutedEventArgs e)
{
    DispatcherTimer timer = new DispatcherTimer();
    timer.Tick += new EventHandler(timer_Tick);
    // Esegue ogni 5 secondi
    timer.Interval = TimeSpan.FromSeconds(5);
    // Avvio il timer
    timer.Start();
}
void timer_Tick(object sender, EventArgs e)
{
    // Eseguo
}

L'evento Tick ha la particolarità di essere eseguito come operazione accodata nel Dispatcher perciò avviata, quando possibile, sul thread UI. Sebbene in condizioni normali la coda è solitamente vuota o comunque smistata velocemente, non è detto che l'evento venga eseguito, come nell'esempio visto, esattamente ogni cinque secondi, ma non vi sono alternative e la classeDispatcherTimer è l'ideale se si deve interagire con l'interfaccia grafica.

Un secondo metodo per eseguire operazioni ad intervalli è costituito dalla classe Timer (namespace System.Threading.Timer). Le funzionalità e il suo utilizzo sono le medesime del .NET Framework e permette di eseguire un delegate ad una funzione:

void startTimer2_Click(object sender, RoutedEventArgs e)
{
    Timer timer = new Timer(OnTimer, null, 2000, 5000);
}

void OnTimer(object state)
{
    // Eseguo
}

Il costruttore della classe accetta la funzione, un eventuale parametro di stato, i millisecondi che devono passare per la prima esecuzione e quelli per le successive esecuzioni. Una volta creato il ciclo parte all'infinito fino a quando non si chiama Dispose. La principale differenza rispetto al DispatcherTimer risiede nell'esecuzione del delegate che in questo caso avviene su un thread a parte, non quello del Dispatcher, ma appartenente ad un pool di thread già pronti all'uso. In generale quindi si consiglia di usare questa classe solo per eseguire operazioni che non intervengono sull'interfaccia e soprattutto che impiegano più tempo di elaborazione.

4 pagine in totale: 1 2 3 4
Contenuti dell'articolo

Commenti

Visualizza/aggiungi commenti

| Condividi su: Twitter, Facebook, LinkedIn

Per inserire un commento, devi avere un account.

Fai il login e torna a questa pagina, oppure registrati alla nostra community.

Approfondimenti

Nessuna risorsa collegata