By paddloPayday loans

Home > Concurrent Programming, Parallel Programming > Concurrent Programming and Parallel Patterns

Concurrent Programming and Parallel Patterns

concurrentConcurrent Programming Patterns

If you’ve viewed the posts that we’ve had on both parallel (//P) and concurrent (||P) programming, most of what you’ve seen has been long-standing attempts at borrowing what’s been published on parallel programming and applying it to ActionScript 3.0. The examples originated in other languages, especially in C#, and attempting to simulate parallel programming in AS3 has been more hope than reality. However, now that all of the development software has been made available (at least in Adobe Labs), you can write honest-to-goodness ||P programs with ActionScirpt 3.0. You’ll need Flash Builder 4.7 or newer, and the latest Flash player. (I have not tried this with Flash CS6 yet, but feel free to do so and let me know how it works out.) At this time, the concurrent programming features are only available for desktop AIR 3.4+; so forget about using workers for developing mobile apps at this point in time.

Why Concurrent Programming?

Design patterns in ActionScript 3.0 (or any other language) are not for speeding up programs. They are for speeding up development time. Re-use is the key to understanding and effectively using design patterns. However, concurrent programs are decidedly for speeding up programs. A task is given to more than one worker (a Primordial Worker and Background Worker(s)). By having two processes running simultaneously, the program should run faster. (For more details on how Adobe has implemented this model see the Concurrent Graphic Novel on this blog and anything written by Thibault Imbert on the topic.)

Despite the fact that design patterns in computer programming are associated with speeding up development time, the design patterns in Design Patterns for Decomposition and Coordination on Multicore Architectures by Colin Campbell, Ralph Johnson, Ade Miller, and Stephen Toub are all about using parallel programming (in C#) for writing programs with certain built-in features that use C# statements that call parallel operations. (See the chapter on Parallel Loops.) For example, C# has statements like Parallel.For() and Parallel.ForEach().

In ActionScript 3.0, we do not have a set of for statements to use with ||P, but we do have statements that will allow us to speed things up by dividing a single task into multiple ones that are handled simultaneously. While AS3 statements are different than those used with //P, we can go ahead and make concurrent versions of parallel programming design patterns. The place to start is with with Parallel Loops. (See Parallel Loops: The First Multicore Design Pattern on this blog.) Essentially, a Concurrent Loop is the same as a Parallel Loop in that a single task is broken down into two (or more) tasks and handled simultaneously. By “broken down” I refer to decomposition. (See the post on decomposition on this blog for more details.) However, instead of decomposition breaking down tasks handled by separate cores, in concurrent programming in AS3, they’re handled by separate workers.

An Example of a Concurrent Loop Using Workers

In previous attempts at creating simultaneously running loops in ActionScript 3.0, I could not get the speed advantage because of the Rube Goldberg contraptions I constructed. So the first challenge is to create a loop and first run it with two or more workers acting concurrently and compare it with a single loop with no concurrent component. If everything went according to plan, two concurrent loops could process a set number of iterations twice as fast as a single loop. After setting up a timer and some helper classes, I tested it, and it worked. I set up a loop with 200 million iterations. The concurrent loop was handled by two workers, each with 100 million iterations. After both workers were done, a timer would show how long the operation took. The same was done with a single loop using the same timer. It took twice as long. Click on the Play button to see. (You can download all of the source code and helpers as well.)

play buttondownload this sucker

When you click on the Play button, you can start the concurrent loop and single loop separately. You’ll see that the concurrent loop and make the same number of iterations in about half the time of the single loop.

Two Workers; One Task

The LoopTest class is embarrassingly long (mainly formatting), but the core of the class is in the setWorkerChannels() method. By default, the current Worker is the primordial worker, and it can create any number of background workers. The primordial worker is created by default, and it then creates a message channel to the background worker(s). In this example, workerB is the background worker. The background worker is declared as an instance of the Worker class and instantiated in the context of the primordial worker using a ByteArray() object (byteMeArray.)

?View Code ACTIONSCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package
{
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.system.MessageChannel;
	import flash.system.Worker;
	import flash.system.WorkerDomain;
	import flash.system.WorkerState;
	import flash.text.TextField;
	import flash.utils.ByteArray;
 
	import uifactory.*
 
	public class LoopTest extends Sprite
	{
		private var workerB:Worker = null;
		private var backToMain:MessageChannel;
		private var mainToBack:MessageChannel;
		//UI package
		private static var display:UICreator;
		private static var displayNow:TextField;
		private static var btn:UICreator;
		private static var btnNow:Sprite;
		private static var btnS:UICreator;
		private static var btnNowS:Sprite;
		//Timer
		private var timeKeeper:TimeKeeper=new TimeKeeper();
		private var expense:Number;
 
		public function LoopTest()
		{
			displaySetup();
			setWorkerChannels();
		}
		private function setWorkerChannels():void
		{
			var byteMeArray:ByteArray = new ByteArray();
			byteMeArray = this.loaderInfo.bytes;
 
			if (Worker.current.isPrimordial) 	
			{		
				//Worker.current is primordial worker here
				workerB = WorkerDomain.current.createWorker(byteMeArray);
				mainToBack = Worker.current.createMessageChannel(workerB);
				backToMain = workerB.createMessageChannel(Worker.current);
				workerB.setSharedProperty("incoming",mainToBack);
				workerB.setSharedProperty("outgoing",backToMain);
				backToMain.addEventListener(Event.CHANNEL_MESSAGE, mainMessageHandler);				
				workerB.start();
			}
			else 
			{	
				//Worker.current is background worker here
				mainToBack = Worker.current.getSharedProperty("incoming");
				backToMain = Worker.current.getSharedProperty("outgoing");
				mainToBack.addEventListener(Event.CHANNEL_MESSAGE,backgroundMessageHandler);
			}
		}
 
		private function mainMessageHandler(e:Event):void
		{
			if (e.target.messageAvailable == true)
			{
				var loopSize:uint = e.target.receive();
				if(loopSize==86)
				{
					displayNow.appendText("Background Worker done\n");
					expense=timeKeeper.endTime()
					displayNow.appendText("Elapsed time:"+String(expense));
				}
				for(var l2:uint=100000000;l2 < loopSize;l2++)
				{
					if(l2>=loopSize-1)
					{
						displayNow.appendText("Primordial Worker done\n");
					}
				}
			}
		}
		private function backgroundMessageHandler(e:Event):void
		{
			if (e.target.messageAvailable == true)
			{
				var loopSize:uint = e.target.receive();
				backToMain.send(200000000);
				for(var l1:uint=0;l1 < loopSize;l1++)
				{
					if(l1>=loopSize-1)
					{
						backToMain.send(86);
					}
				}
			}
		}
 
		private function sendMsg(e:MouseEvent):void
		{
			displayNow.appendText("Starting both loops:\n\n");
			timeKeeper.startTime();
			mainToBack.send(100000000);
		}
 
		private function singleLoop(e:MouseEvent):void
		{
			displayNow.appendText("\n\nStarting single loop:\n\n");
			timeKeeper.startTime();
			var singleSize:uint=200000000;
			for(var sl:uint=0;sl < singleSize;sl++)
			{
				if(sl>=singleSize-1)
				{
					singleTime();
				}
			}
		}
 
		private function singleTime():void
		{
			expense=timeKeeper.endTime();
			displayNow.appendText("Elapsed time:"+String(expense)+"\n\n");
		}
 
		private function displaySetup():void
		{
			btn = new SpriteButtonMaker();
			btnNow=btn.factoryMethod("Start Concurrent Loop",10,10,0xBFA473,180,40);
			btnNow.addEventListener(MouseEvent.CLICK,sendMsg);
			addChild(btnNow);
 
			btnS = new SpriteButtonMaker();
			btnNowS=btnS.factoryMethod("Start Single Loop",10,60,0xBFA473,180,40);
			btnNowS.addEventListener(MouseEvent.CLICK,singleLoop);
			addChild(btnNowS);
 
			display=new TextDisplayMaker();
			displayNow = display.textFactoryMethod("DYNAMIC",10,120,0xD5E7C2,400,200);
			addChild(displayNow);
		}
	}
}

Note: All of the other classes used for timing and formatting in this example are available in the download package and will not be discussed here. However, you might want to open them so you can see how they’re related to the LoopTest class.

As an OOP process, creating and programming with workers is very natural in the sense that most of the work is setting up and using message channels and shared properties. It’s a matter of objects communicating with one another. Within the primordial worker context, the background worker sends it first message when the Worker.start() method. Once the background worker starts working, it’s state (status) is shared with the primordial worker through messaging and shared properties and vice versa.

Is a Concurrent Loop a Design Pattern?

The issue of whether or not the Concurrent Loop (conceptually the same as a Parallel Loop) is a design pattern because Colin Campbell, Ralph Johnson, Ade Miller, and Stephen Toub say it is stands at the crux of the issue. In C#, the built-in statements for parallel loops somehow look less like design patterns and more like statements and nothing more. (See the Parallel Loops post on this blog.) Rather than having to build a concurrent loop as is done in this post’s example, if all that was required was a concurrent loop statement such as Concurrent.for(), I’m not sure what it would be. Certainly some languages have built-in design patterns, and so because an operation is built into the language does not preclude it from being a design pattern. Anyway, it is certainly the stuff for discussion, and I hope to hear from some of you who have opinions and ideas on this new ActionScript 3.0 arena.

Share
  1. Andrew
    January 3, 2013 at 6:55 am | #1

    Looks great, thanks for putting this together!
    Quick comment – AIR (desktop) does support workers as of 3.4, though this does seem a bit buggy still. See AS3 ‘Worker’ documentation. Not sure why Adobe’s release notes say that Workers are just “Flash Player only” though…

    • William B. Sanders
      January 3, 2013 at 10:19 am | #2

      Hi Andrew.

      You are correct! My bad. I now think AIR = Mobile app development, but AIR 3.4 desktop does accept workers.(I fixed it in the write-up. I thank you.)

      Kindest regards,
      Bill

  2. doug
    January 10, 2013 at 12:46 am | #3

    Hello William, thank you for the great write up on workers. I had a question on one part, is the StartConcurrentLoop actually running 3 million times instead of 2 million? It looks like the worker is doing 1mil operations and then it is doing backToMain.send with 2mil operations, is that 3mil total? Thank you

    • doug
      January 10, 2013 at 12:52 am | #4

      Oh my bad, I didnt notice that the loop already started at 1 mil.

      • William B. Sanders
        January 10, 2013 at 9:44 pm | #5

        Hi Doug,

        Glad you caught it before I went nuts! Both the worker (primordial) and the background worker share in the task, and it actually works!

        Let me know if you can use it in a practical app!

        Kindest regards,
        Bill

  1. January 2, 2013 at 9:51 am | #1

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>