This article is following “Multithreading” in ActionScript
Again, I’m going to start the atricle with:
Multithreading in ActionScript, no such thing!
Yes, they cooked PixelBender, that is very cool. You can do computations in the bender, they run asynchronously and are faster than ActionScript.
But now, let’s come back to our stuff. We are talking about ActionScript and code slicing, so the interface doesn’t get locked while your ActionScript program runs.
Here is one example, maybe this particular one can be better done with Bender, but it can serve as an example of how you can change a double “for” loop into slices for IThread.
We take an image and feed it into the JPGEncoder. The encoder outputs the jpeg file into a BitmapData instance. Then we load the BitmapData using a Loader, just to check the process was completed successfully.
You can see the progressbar advancing only in the threaded version. In the standard one, you can’t even move the browser window while processing. The threaded version takes a bit longer, depending on how much you interact with the interface.
Note: Someone suggested that dispatching events is slower than using function references directly. This example shows that the time penalty for using events is negligible, because events are not sent at each slice execution, but rather only on frame event and ready event, and those are quite few.
Here is the original main loop in Adobe’s JPGEncoder (corelib http://code.google.com/p/as3corelib/)
public function encode(image:BitmapData):ByteArray { // Initialize bit writer byteout = new ByteArray(); bytenew=0; bytepos=7; // Add JPEG headers writeWord(0xFFD8); // SOI writeAPP0(); writeDQT(); writeSOF0(image.width,image.height); writeDHT(); writeSOS(); // Encode 8x8 macroblocks var DCY:Number=0; var DCU:Number=0; var DCV:Number=0; bytenew=0; bytepos=7; for (var ypos:int=0; ypos<image.height; ypos+=8) { for (var xpos:int=0; xpos<image.width; xpos+=8) { RGB2YUV(image, xpos, ypos); DCY = processDU(YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT); DCU = processDU(UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); DCV = processDU(VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); } } // Do the bit alignment of the EOI marker if ( bytepos >= 0 ) { var fillbits:BitString = new BitString(); fillbits.len = bytepos+1; fillbits.val = (1<<(bytepos+1))-1; writeBits(fillbits); } writeWord(0xFFD9); //EOI return byteout; }
And here is the modified code
//thread job context private var started:Boolean = false; private var DCY:Number; private var DCU:Number; private var DCV:Number; private var image:BitmapData; private var ypos:int; private var xpos:int; public var progress:Number; public function runSlice():Boolean { if (!started) { // Initialize bit writer byteout = new ByteArray(); bytenew=0; bytepos=7; DCY=0; DCU=0; DCV=0; // Add JPEG headers writeWord(0xFFD8); // SOI writeAPP0(); writeDQT(); writeSOF0(image.width,image.height); writeDHT(); writeSOS(); xpos = 0; ypos = 0; started = true; } progress = ypos / image.height; RGB2YUV(image, xpos, ypos); DCY = processDU(YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT); DCU = processDU(UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT); DCV = processDU(VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT); xpos += 8; if (xpos >= image.width) { ypos += 8; xpos = 0; } //we are ready if (ypos >= image.height) { // Do the bit alignment of the EOI marker if ( bytepos >= 0 ) { var fillbits:BitString = new BitString(); fillbits.len = bytepos+1; fillbits.val = (1<<(bytepos+1))-1; writeBits(fillbits); } writeWord(0xFFD9); //EOI return false;//job finished } //wait for next slice return true; }
Test the application here: example
You can compare the execution time. Note how the interface is still responsive while processing the threaded version.
Download: ThreadsExample ActionScript project


