Showing posts with label workers. Show all posts
Showing posts with label workers. Show all posts

Friday, August 10, 2012

Intro to AS3 Workers (Part 3): NAPE Physics + Starling!

In part 1 of this series we looked at the basic message protocol for AS3 Workers, and a simple hello world.
In part 2, we looked at an example of performing imageProcessing in a seperate thread.
In this final installment, I’ll show how you can run your Physics entirely on a seperate thread, and we’ll also throw in a little Starling to the mix as some icing on the cake :)
Here’s an example of what we’re making:


Note: If you can’t see the SWF, make sure you have downloaded Flash Player 11.4. Chrome user’s, don’t forget to disable the old version.

As a comparison, here’s an optimized Haxe Demo rendered in CPU mode with Physics done in the main thread:
http://deltaluca.me.uk/docnew/swf/StressPyramid.html
On most computers the single threaded test will struggle to reach >45fps. With the CPU completely maxed out. Even if you do manage to hit 60fps because you have a super fast CPU, you;re still totally maxed out, you would have no more room at all to do anything else in your game. Contrast that to the Worker implementation, where the main thread is doing virtually nothing on the CPU. It spends <1ms on de-serializing the data, and a couple more pushing a bunch of vertex's to Starling. It has so much free time it's taking a smoke break!

Overview

First a quick overview of how this will work:
  • The Nape simulation will live entirely inside a Worker thread
  • The Main Thread will make calls on the Worker Thread when it wants to add a new Physics Body
  • Each frame, the Worker Thread will copy the position data of all bodies into a shared ByteArray
  • The Main Thread will read the position data from the ByteArray, and use it to update the on-screen Sprites
We’ll start by looking at the document class, and the messages that it sends to the Worker. Then we’ll look at the Worker which contains the actual physics code.

Document Class

The first step is to setup our worker and some message channels so we can talk.
At this point you should be familiar with this boiler-plate code for a Worker-based application: [...]
Read more: Intro to AS3 Workers (Part 3): NAPE Physics + Starling!

Tuesday, August 7, 2012

Intro to AS3 Workers (Part 2): Image Processing

In Part 1 of my Intro to AS3 Workers series I looked at the fundamentals of AS3 workers, including the various communication methods, and showed an example of a simple Hello World worker. In this next post, I’ll take it a step further and show how you can start doing something useful, like image processing! In this case, I’ll be applying a Sharpen Filter to a large bitmap, while the main UI thread continues to render at 30fps. First a demo. In order to view these swf’s:
DEMO: Single-Threaded Here you can take a look at what we’re going to make. This version does not use workers, and you can see that the slider locks up completely as the image is processed:
Make sure you have downloaded and enabled Flash Player 11.4.
DEMO: Multi-Threaded Here is the same demo, but using a Worker. You can see the UI renders at a smooth 30fps:
Make sure you have downloaded and enabled Flash Player 11.4.

The Code

Before actually jumping into the code, it’s important to plan ahead. Especially when dealing with concurrency, we really need to create an efficient system for marshaling data between the workers, otherwise your main thread will begin to bog down due to the heavy cost of serializing and de-serializing data. After a bit of a thought, I decided to architect the app like so:
  • The bitmapData would be shared with the worker using  a shareable byteArray
  • We will use the bitmapData.setPixels(), and bitmapData.copyPixelsToByteArray() API’s to convert the bitmap > byteArray, and vice versa.
  • The main thread will issue “SHARPEN” commands to the worker, and the worker will send “SHARPEN_COMPLETE” when it’s done
  • The worker will use a 500ms timer to check whether it needs to run a new Sharpen operation. This prevents excessive Sharpen operations.
The Document Class First up is the constructor, here we’ll use the same loaderInfo.bytes trick as we did in the last tutorial. This constructor is run twice, the second instance is the worker, and it creates a SharpenWorkerinstance which will handle all communication back to the main thread [...]
Read more: Intro to AS3 Workers (Part 2): Image Processing

Saturday, August 4, 2012

Intro to AS3 Workers: Hello World

With the beta release of AIR 3.4 and Flash 11.4, Adobe has introduced one of the most requested API’s for years: Multi-threading!
With AS3 workers it’s now very easy to create true multi-threaded applications with just a few lines of code. The API is fairly straightforward, and they’ve done some very handy things like a new ByteArray.shareable property to share memory between worker’s, and a new BitmapData.copyPixelsToByteArray API for quickly converting bitmapData to ByteArray.
In this post I’ll go through the various components of the Worker API, and we’ll look at a simple little HelloWorker application.
If you would like to follow along, you can download the FlashBuilder Project Files:

So what is a worker?

Put simply a worker is just another SWF that’s running alongside your main SWF. For a an in depth background check out Thibault Imbert’s excellent writeup.
To create a worker you call WorkerDomain.current.createWorker()  function and pass it the bytes of a SWF.
There’s currently 3 ways to generate these SWF bytes:
  1. Use the loaderInfo.bytes of the main SWF, and check the Worker.current.isPrimordial property inside your document class’s constructor. This is the quickest way to create a worker, and has the advantage of instant testing-debug cycle.
     
  2. Publish a SWF file, and [Embed] it in your main project. This will have tooling support in FlashBuilder 4.7, but until then it’s quite cumbersome. Everytime you change the code in your worker, you must re-export the SWF, this gets annoying pretty quick!
     
  3.  Use Worker From Class a new Library which allows you to create workers directly from Classes. This looks like the most optimal solution right now, but does  introduce a couple of external dependencies in your project.
     
In this initial tutorial I’m going to focus on the first method, using our own loaderInfo.bytes. This is the quick and dirty way to do it. In a follow up tutorial I’ll take a look at Worker From Class.
For a great tutorial on method #2 check out Lee Brimelow’s video’s part 1 and part 2.

Lets talk.

In any multi-threaded scenario communication is key. Transferring memory from one thread to another is expensive, and sharing memory takes careful planning and consideration. Much of the challenge in implementing a worker system comes from finding the right architecture for sharing data to and from your workers.
To help us out Adobe has given us a few simple (but flexible) ways to send messages.

worker.setSharedProperty() / worker.getSharedProperty()

This the simplest but most limited way to pass values around. You can call worker.setSharedProperty(“key”, val) to set things, and WorkerDomain.current.getSharedProperty(“key”) to get them on the other side. You can store both simple and complex objects here, but for most cases the data is serialized, it’s not actually shared. If a value changes on one end, it will not be updated on the other until you call share/get again.
The exception is if you pass a ByteArray with byteArray.shareable=true, or a MessageChannel. Coincidentally, these are the other two methods of communication :)

MessageChannels

MessageChannels are like one way conduits from one worker to another, and they’re event based. So, you will call channel.send() on one end, and channel.receive() on the other. To know when a new message has arrived, you just listen on the channel for Event.CHANNEL_MESSAGE. Messages are queued up and received in the order they were sent.
MessageChannels are shared using worker.setSharedProperty(), and can be shared throughout as many workers in your Application as you would like, but they only ever have one destination. As such, it seems to be a good convention to name them by their receiver, ie channelToWorker or channelToMain
An important limitation to both MessageChannel and sharedProperties, is that the data is serialized when it is sent. That means it needs to be deconstructed, transferred, and reconstructed on the other side. This can be costly. Due to this limitation, these API’s are best used for transfering small amounts of data intermittently. Ideally just simple strings or numbers.
So what if you do need to share a huge chunk of data? The answer is a shareable ByteArray…

byteArray.shareable

The fastest way to transfer data is to not transfer it at all!
Thankfully Adobe has given us the ability to share a ByteArray directly. Since we can store virtually anything inside a ByteArray, this is extremely powerful. To share a byteArray, you set  byteArray.shareable=true and then use messageChannel.send(byteArray) or worker.setSharedPropert(“byteArray”, byteArray) to share it.
Once your byteArray is shared, you can write into it, and read from it on the other end instantly. Beautiful :)
That is basically all there is to it. As you can see, there are 3 distinct ways to share data, and you could combine them in many many different ways. Now that we’ve gone over the structure, lets look at a simple Hello World.

Sample Application

First, in order to get your projects compiling, you’ll need to do a couple things:
  • Download the latest AIR 3.4 SDK, or playerglobal.swc file, make sure your project is using them.
  • Add compile flag “swf-version=17″ to your project
  • Install FlashPlayer 11.4 standalone debugger
With that, you should now see the various Worker related API’s such as Worker, WorkerDoman, MessageChannel etc. If you’re having trouble with this, check out the first couple minutes of Lee Brimelow’s video where he walks through setup.
You can also just download a copy o my FlashBuilder Project which should just work.

Step 1 – The Document Class

First we’ll need to create our document class: [...]
Read more: Intro to AS3 Workers: Hello World