Vectors vs. Linked Lists in AS3

One of the new features in Flash Player 10 was the Vector class, essentially a typed Array. For many operations it gives a substantial performance boost compared to Array.  See Mike Chambers’ blog posts for an introduction on using Vectors and for Vector/Array Performance Comparison.  While Vector is definitely faster than Array, if you mainly need to access values in sequence you can actually get better performance using linked lists.

Consider adding two Vectors of Numbers, with the results stored in a third Vector.  This is very common in audio signal processing – it’s how you mix two signals. The code would look something like this:

const N:uint = 1000;
var xVec:Vector.<Number> = new Vector.<Number>(N);
var yVec:Vector.<Number> = new Vector.<Number>(N);
var zVec:Vector.<Number> = new Vector.<Number>(N);

// ...Stuff some values into xVec and yVec...

// Do element-by-element addition of xVec and yVec, and put
// the results into zVec.
for ( k = 0; k < N; k++ )
{
	zVec[k] = xVec[k] + yVec[k];
}

It’s simple and straightforward, and gives decent performance, especially compared to the equivalent code using Arrays.  Suppose instead we use linked lists.  Each linked list element needs to store a Number, and a link (pointer/reference) to the next element:

final class LinkedNumber
{
	public var val:Number  = 0.0;
	public var next:LinkedNumber = null;
}

Now suppose we’ve created three linked lists X, Y, and Z, with heads xHead, yHead, and zHead. To add the elements in X and Y, and put the result into Z, we would write this:

var xLink:LinkedNumber = xHead;
var yLink:LinkedNumber = yHead;
var zLink:LinkedNumber = zHead;

for ( k = 0; k < N; k++ )
{
	zLink.val = xLink.val + yLink.val;
	xLink = xLink.next;
	yLink = yLink.next;
	zLink = zLink.next;
}

I’ve written a simple test program to compare the performance of the Array, Vector and linked list approaches.  It adds up Arrays/Vectors/linked lists with 5000 elements, and repeats it 5000 times. Click “show source” to see the full code:

package
{
	import __AS3__.vec.Vector;
	import flash.display.*;
	import flash.text.*;
	import flash.utils.getTimer;

	/**
	 * A comparison of the speed of computation using Vectors,
	 * Arrays, and linked lists.
	 *
	 * @author Gerry Beauregard
	 */
	[SWF(width='400',height='70',backgroundColor='0x777777')]

	public class LinkedListSpeedTest extends Sprite
	{
		private const N:uint = 5000;		// No. of elements in vectors/arrays/linked lists
		private const LOOPS:uint = 5000;	// No. of times to repeat the calculations

		public function LinkedListSpeedTest()
		{
			var elapsedTime:int;

			// Set up a text field to show the results
			stage.align = StageAlign.TOP_LEFT;
			stage.scaleMode = StageScaleMode.NO_SCALE;

			var textField:TextField = new TextField;
			textField.autoSize = TextFieldAutoSize.LEFT;
			textField.selectable = true;
			textField.defaultTextFormat = new TextFormat( 'Verdana', 12, 0xFFFFFF );
			addChild( textField );

			textField.text = "Time (ms)\n";

			elapsedTime = arrayTest();
			textField.appendText("Array: " + elapsedTime + "\n");

			elapsedTime = vectorTest();
			textField.appendText("Vector: " + elapsedTime + "\n");

			elapsedTime = linkedListTest();
			textField.appendText("LinkedList: " + elapsedTime + "\n");
		}

		/**
		 * Add elements of one Array to elements of another
		 * Array, and put the results into a third Array.
		 */
		private function arrayTest():int
		{
			// Create vectors
			var xArr:Array = new Array;
			var yArr:Array = new Array;
			var zArr:Array = new Array;

			// Initialize them with some values
			for ( var k:uint = 0; k < N; k++ )
			{
				xArr[k] = k;
				yArr[k] = k;
				zArr[k] = 0.0;
			}

			// Add the values in the two vectors, with result
			// in a third vector.  Repeat many times.
			var startTime:int = flash.utils.getTimer();
			for ( var j:uint = 0; j < LOOPS; j++ )
			{
				for ( k = 0; k < N; k++ )
				{
					zArr[k] = xArr[k] + yArr[k];
				}
			}
			var endTime:int = flash.utils.getTimer();

			return (endTime - startTime);
		}

		/**
		 * Add elements of one Vector to elements of another
		 * Vector, and put the results into a third Vector.
		 */
		private function vectorTest():int
		{
			// Create vectors
			var xVec:Vector.<Number> = new Vector.<Number>(N);
			var yVec:Vector.<Number> = new Vector.<Number>(N);
			var zVec:Vector.<Number> = new Vector.<Number>(N);

			// Initialize them with some values
			for ( var k:uint = 0; k < N; k++ )
			{
				xVec[k] = k;
				yVec[k] = k;
				zVec[k] = 0.0;
			}

			// Add the values in the two vectors, with result
			// in a third vector.  Repeat many times.
			var startTime:int = flash.utils.getTimer();
			for ( var j:uint = 0; j < LOOPS; j++ )
			{
				for ( k = 0; k < N; k++ )
				{
					zVec[k] = xVec[k] + yVec[k];
				}
			}
			var endTime:int = flash.utils.getTimer();

			return (endTime - startTime);
		}

		/**
		 * Add elements of one linked list to elements of another
		 * linked list, and put the results into a third linked list.
		 */
		private function linkedListTest():int
		{
			// Create linked lists of Numbers
			var xHead:LinkedNumber = createLinkedNumberVec(N);
			var yHead:LinkedNumber = createLinkedNumberVec(N);
			var zHead:LinkedNumber = createLinkedNumberVec(N);

			// Initialize them with some values
			var xLink:LinkedNumber = xHead;
			var yLink:LinkedNumber = yHead;
			var zLink:LinkedNumber = zHead;
			for ( var k:uint = 0; k < N; k++ )
			{
				xLink.val = k;
				yLink.val = k;
				zLink.val = 0.0;
				xLink = xLink.next;
				yLink = yLink.next;
				zLink = zLink.next;
			}

			// Multiply the values in the two linked lists, with result
			// in a third linked list.  Repeat many times.
			var startTime:int = flash.utils.getTimer();
			for ( var j:uint = 0; j < LOOPS; j++ )
			{
				xLink = xHead;
				yLink = yHead;
				zLink = zHead;

				for ( k = 0; k < N; k++ )
				//while ( xLink )  // << Slightly faster than the for loop.
				{
					zLink.val = xLink.val + yLink.val;
					xLink = xLink.next;
					yLink = yLink.next;
					zLink = zLink.next;
				}
			}
			var endTime:int = flash.utils.getTimer();

			return (endTime - startTime);
		}

		/**
		 * Create a linked list of LinkedNumber elements
		 */
		private function createLinkedNumberVec(n:uint):LinkedNumber
		{
			var next:LinkedNumber = null;
			for ( var k:uint = 0; k < n; k++ )
			{
				var current:LinkedNumber = new LinkedNumber;
				current.next = next;
				next = current;
			}

			return current;
		}
	}
}

/**
 * Linked list element containing a Number value.
 */
final class LinkedNumber
{
	public var val:Number  = 0.0;
	public var next:LinkedNumber = null;
}

Here are typical times I get on my old MacBook Pro (2 GHz Intel Core Duo, OS 10.6.4) using a Release Build SWF (built with Flex Builder 3, and Flex SDK 3.2), and Flash Player 10.1.53.64. The times vary a bit from run to run, but not by much.

Approach Time (ms)
Array 1292
Vector 693
Linked List 289

Using Vectors gives you a nice performance boost compared to using Arrays, but clearly linked lists blow both away.

In some ways, this is a pity. The linked list code is messier and less intuitive. What’s more, if you need fast sequential access to the elements but also sometimes need random access, you need to use a linked list but also keep the elements in a Vector. (See An even faster AS3 FFT for an example).

If Adobe wants to make AS3 be a reasonably high performance language, improving the performance of sequential access to Vector elements would be a good place to start. Perhaps this would be possible via a tweak to the compiler and/or player?

Advertisement

About Gerry Beauregard

I'm a Singapore-based Canadian software engineer, musician, inventor, father, traveler, and "try"-athlete. I like to imagine that I have interesting thoughts to share with the world, and this is my way of sharing those thoughts with my (imaginary?) audience :-) I'm Lead Software Architect for Sonoport, a little startup that makes AS3 interactive audio components. Past jobs include writing speech recognition software for Apple, creating automatic video editing software for muvee, and delivering newspapers for the Montreal Gazette.
This entry was posted in Audio, Flash, Programming. Bookmark the permalink.

2 Responses to Vectors vs. Linked Lists in AS3

  1. Alama says:

    Nice! Nice! Nice! André Michèleis crazy but awesome !! :D thank for work, great!

  2. Jacob Harrison says:

    Great article!

    Now, I am going to have to refactor some of my data!

    Thanks for sharing this.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s