Green Threads risolve actionscript3 senza multi-threads

AS3, Flex oscar Commenta l'articolo

Green Threads

In action script non possiamo usare un vero sistema di multi thread, ma qualunque linguaggio può simularere i muti thread, questa tecnica viene chiamata Green Threads. Molti linguaggi hanno già utilizzata questa tecnica. I threads in Ruby sono ancora green e anche le prime versioni di java lo erano. Drew Cummins implementa una versione di ciò per Flashplayer10. Chubbard ha riscritto tutto rimuovendo le dipendenze da FlashPlayer10 e cambiato qualche API così gli eventi lanciati sono più naturali, aggiungendo prima eventi di progress e opzionali progress tracking.

Vediamo un esempio:

public class Mandelbrot extends GreenThread {
private var _bitmap : BitmapData;
private var _maxIteration : uint = 100;
private var _realMin : Number = -2.0;
private var _realMax : Number = 1.0;
private var _imaginaryMin : Number = -1.0;
private var _imaginaryMax : Number = 1.0;
private var _shader : Shader;

private var _realStep : Number;
private var _imaginaryStep : Number;
private var screenx : int = 0;
private var screeny : int = 0;

override protected function initialize( ) : void {
_bitmap = new BitmapData( width, height, false, 0x020202 );
screenx = screeny = 0;
_realStep = (_realMax - _realMin) / Number(_bitmap.width);
_imaginaryStep = ( _imaginaryMax - _imaginaryMin ) / Number( _bitmap.height );
}

override protected function run():Boolean {
if( screenx > _bitmap.width ) {
screenx = 0;
screeny++;
}
if( screeny < _bitmap.height ) {
var x : Number = screenx * _realStep + _realMin;
var y : Number = screeny * _imaginaryStep + _imaginaryMin;
var x0 : Number = x;
var y0 : Number = y;
var iteration : int = 0;
while( x * x + y * y <= (2 * 2) && iteration < _maxIteration ) {
var xtemp : Number = x * x - y * y + x0;
y = 2 * x * y + y0;
x = xtemp;
iteration = iteration + 1;
}

if( iteration == _maxIteration ) {
_bitmap.setPixel( screenx, screeny, 0x000000 );
} else {
_bitmap.setPixel( screenx, screeny, shader.lookup( Number(iteration) / Number(maxIteration) ) );
}
screenx++;
return true;
} else {
return false;
}
}
}

Il metodo run() è il corpo del ciclo. Il metodo intialize() viene chiamato dopo che l'utente chiama i metodo start(). Il metodo run() viene ripetutamente chiamato fin quando non ritorna false. E' concesso chiamare più di una volta il metodo start() per far ripartire il thread dopo la sua fine. Questo significa che puoi calcolare il "Mandelbrot" settando differenti livelli di zoom senza necessariamente ricreare una nuova istanza. Il metodo initialize() viene chiamato ogni volta viene chiamato il metodo start(). Verifica il risultato qui.
Puoi anche addizionare progress tracking opzionali settando le proprietà (variabili) maximum e progress. Questo lancerà automaticamente un evento ProgressEvents così da poterlo catturare all'interno del metoto run().
Nel complesso abbiamo risolto il problema delle performance o ci siamo avvicinati molto. Ciò che rimane appeso è la risoluzione del getTimer(), in fatti abbiamo solo la precisione di millesecondi e noi non possiamo eseguire un thread ad un tempo inferiore di un millisecondo per DELTA. Questo ci costa poche iterazioni sul metodo run() che può fare la differenza su 1000 cicli.
Ci sono poche cose che possiamo fare per stringere un po' di più le perfomance di GreenThreads.

Il frame rate governa qualunque cosa facciamo e per default Flex esegue un frame rate di 24 fs. Flex realizza molte animazioni e se dimezziamo il frame rate a 12 fs allora vedremmo un "run" molto lungo senza interruzioni. Poche interruzioni abbiamo e più veloce sarà l'applicazione.
Anche GreenThreads permette di configurare quanti frame dedichi all'esecuzione del thread. Per default è settato a 0,99 che approssimativamente lascia 1 ms per aggiornare l'interfaccia (UI). Con qualche esperimento questo ha dimostrato un lavoro completamente buono senza creare molti timeouts, ma se vuoi modificare tale valore fornendo un nuovo valore allora procedi come segue:

public function go() : void {
start( 0.5 );
}

Il parametro minore di uno rappresenta la percentuale della lunghezza del frame. Se è maggiore o uguale a uno esso rappresenta i millisecondi da sottrarre alla lunghezza del frame. E' necessario fare altre riflessioni riguardo a ciò, perché la tua applicazione gira su differenti macchine con differenti CPU, quindi la pausa deve essere appropriata per ogni CPU. In futuro sarà necessario aggiustare l'esecuzione dell'algornitmo dinamicamente.

GreenThreads supporta delle statistiche in runtime per tracciare il tuo job. Per consentire le statistiche è necessario settare a true il costruttore di GreenThreads. Le statistiche raccolgono il tempo totale preso dal job, il numero di timeouts, il tempo minimo e massimo di iterazioni, la media per l'esecuzione di una singola iterazione, il numero di cicli fatti, ecc..., C'è la giusta quantità di informazioni che possono essere raccolte per aiutarti nella messa a punto del thread. Puoi accedere a queste informazioni così:

public class SomeJob extends GreenThread {

public function SomeJob() {
super( true ); // turn on debug statisitics

addEventListener( Event.COMPLETE, function( event : Event ) : void {
trace( statistics.print() );
});
}
}

Quando costruisci la tua applicazione basata su Green Thread assicurati che ogni operazione non superi i 100 millisecondi, perché superata tale soglia i successivi processi (anche di rendering) potrebbero rallentare. L'unica soluzione è spezzare in ulteriori funzioni il calcolo.

Simulare il multi threads in questo modo può portare ad un rallentamento del rendering e quindi nel visualizzare i componenti GUI, ma è sicuramente migliore una situazione del genere rispetto a non vedere proprio nulla, aspettando che i vari calcoli terminino per vedere la GUI risultante.

Scarica la libreria di GreenThreads qui

Scrivi un Commento

Home | Graffiti e Disegni | Educazione | Chi siamo | Blog | Progetti | Contatti
RSS Feed Comments RSS Accedi