Paul Robertson's words, punctuated

Thoughts on development, user-centered design, code, etc. by Paul Robertson

Slides and code: Concurrent programming with ActionScript workers

Several weeks ago, I gave a presentation to the D-Flex users’ group about the new ActionScript workers features in Flash Player 11.4/AIR 3.4. Although I’m a few weeks behind on this, I wanted to share my slides and code.

Update Nov. 7 2012: On recommendation from Leif Wells, I realized it would be useful to share some links and tips on use cases and best practices for AS3 Workers.

A lot of the presentation involved talking through examples in the slides, but I also showed a “full” code example at the end.

If you’re interested you can view and download the example from GitHub. It’s a simple app that just counts from 0 to 100,000,000 in a loop. The counting happens behind the scenes – it’s not rendered on the screen – but it does have a progress bar and progress status text field that are updated as the counting happens:

Near the start of the presentation I showed a version of the app that does things the “wrong” way (on GitHub this is called the “NonWorkerVersion”). Since the code just counts in a loop, the code blocks in the loop and the UI freezes. (Depending on how busy your machine is and how high the number is, it can trigger a script timeout error.) Of course, the progress bar and the progress status text field don’t update either since they run in the same thread as the loop that’s counting.

This is the loop code, from the main class:

Counting in a loop (non-worker version) NonWorkerDemo.as on GitHub
1
2
3
4
5
6
7
8
9
10
while (i < targetValue)
{
    i++;
    // only send progress messages every so often
    // to avoid flooding the message channel
    if (i % oneHalfPercent == 0)
    {
        handleProgressMessage(i / onePercent);
    }
}

Toward the end of the presentation I showed the version that does things the right way.

First, the UI thread spawns a worker and sets up the main thread-to-worker communication, then it starts running:

Starting up the Worker WorkerDemo.as on GitHub
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
bgWorker = WorkerDomain.current.createWorker(Workers.BackgroundWorker);

bgWorkerCommandChannel = Worker.current.createMessageChannel(bgWorker);
bgWorker.setSharedProperty("incomingCommandChannel", bgWorkerCommandChannel);

progressChannel = bgWorker.createMessageChannel(Worker.current);
progressChannel.addEventListener(Event.CHANNEL_MESSAGE, handleProgressMessage)
bgWorker.setSharedProperty("progressChannel", progressChannel);

resultChannel = bgWorker.createMessageChannel(Worker.current);
resultChannel.addEventListener(Event.CHANNEL_MESSAGE, handleResultMessage);
bgWorker.setSharedProperty("resultChannel", resultChannel);

bgWorker.addEventListener(Event.WORKER_STATE, handleBGWorkerStateChange);
bgWorker.start();

The worker contains the loop that counts. The worker is still just using a loop (and hence is running in a continuous thread without stopping the entire time). However, it dispatches events to the main thread/worker and it updates the display. This is the code for the worker’s counting loop (from “BackgroundWorker.as”):

Counting in a loop (Worker version) BackgroundWorker.as on GitHub
1
2
3
4
5
6
7
8
9
10
while (i < targetValue)
{
    i++;
    // only send progress messages every so often
    // to avoid flooding the message channel
    if (i % oneHalfPercent == 0)
    {
        progressChannel.send(i / onePercent);
    }
}

Even though this is just a simple example, it demonstrates how working with workers requires a bit of mind-bending and changing the way we think about coding in ActionScript. I realized as I started using workers that I’m so used to ActionScript’s single-threaded event-driven execution model that I make some assumptions sometimes about code execution. Once I started splitting my code into workers, I had to change my way of thinking.

On one hand, I realized that with the single-threaded model I subconciously made assumptions about certain things already having been processed or finished executing before other blocks of code were run. However, those assumptions aren’t necessarily true when the code is running in parallel, so I had to be more careful in planning my code to accomodate different states of completion at various milestones.

On the other hand, I was able to be more procedural and less event-driven (within my worker code) and just write all the code within a single method that was mostly a loop. This also requires a different way of thinking about the code. I’m so used to splitting code up into lots of event handlers that it’s weird to think that I can just run code in a loop and dispatch events, and know that they will actually be caught and run in the other thread even though the loop/method I’m in hasn’t returned yet.

Once the Worker apis are complete with the Mutex class and the Condition class, this will allow the potential for even more linear/procedural code. It will be possible to pause a thread’s execution, so you could conceivably write an entire worker within a single loop that never exits and just pauses execution until it’s needed. I know that’s normal in some other programming disciplines, but for an ActionScript programmer it’s a bit mind-bending.

Comments