Constructing Arrays
In AS3, you can create an Array
can be created with special syntax: myArray = []
. You can even fill the Array
with values all in one go: myArray = [1,2,3,4,5]
. This is a nice shorthand that saves some typing compared to using the constructor: myArray = new Array(1,2,3,4,5)
. But, which way is faster? Today we find out! UPDATE: added a third way of creating arrays
I’ve covered declaring Vectors before, but today’s article asks the same sort of questions for Array
: how should we declare them for optimal speed? To reduce typing, the choice is clear. Code clarity is, as usual, subjective and I won’t cover that topic here. Instead, let’s look at a couple of examples:
var a:Array; a = []; a = new Array();
Now let’s look at the bytecode that’s generated by these two Array
initializations:
// a = [] newarray [0] // create the Array coerce Array // make sure it is typed Array setlocal1 // set it to a // a = new Array() findpropstrict Array // find the Array class constructprop Array (0) // call the constructor coerce Array // make sure it is typed Array setlocal1 // set it to a
First off, we have a savings of one instruction in the SWF for using the shorthand. This is because we’re taking advantage of a specialized bytecode—newarray
—rather than relying on the generalized constructor-calling bytecodes. We also avoid the search for the Array
class.
There is a third way as well. A function taking var args (...
) has its var args transformed into an Array
. This Array
can simply be returned. This gives rise to a utility function:
function createArray(...rest): Array { return rest; }
How fast are all of these options? Well, let’s do a test to compare creating Array
objects with zero, five, ten, and twenty elements:
package { import flash.display.*; import flash.utils.*; import flash.text.*; public class ConstructingArrays extends Sprite { public function ConstructingArrays() { var logger:TextField = new TextField(); logger.autoSize = TextFieldAutoSize.LEFT; addChild(logger); var beforeTime:int; var afterTime:int; var i:int; const REPS:int = 1000000; var a:Array; logger.text = "new,[],var args\n"; logger.appendText("0,"); beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { a = new Array(); } afterTime = getTimer(); logger.appendText((afterTime-beforeTime) + ","); beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { a = []; } afterTime = getTimer(); logger.appendText((afterTime-beforeTime) + ","); beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { a = createArray(); } afterTime = getTimer(); logger.appendText((afterTime-beforeTime) + "\n"); logger.appendText("5,"); beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { a = new Array(1,2,3,4,5); } afterTime = getTimer(); logger.appendText((afterTime-beforeTime) + ","); beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { a = [1,2,3,4,5]; } afterTime = getTimer(); logger.appendText((afterTime-beforeTime) + ","); beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { a = createArray(1,2,3,4,5); } afterTime = getTimer(); logger.appendText((afterTime-beforeTime) + "\n"); logger.appendText("10,"); beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { a = new Array(1,2,3,4,5,6,7,8,9,10); } afterTime = getTimer(); logger.appendText((afterTime-beforeTime) + ","); beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { a = [1,2,3,4,5,6,7,8,9,10]; } afterTime = getTimer(); logger.appendText((afterTime-beforeTime) + ","); beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { a = createArray(1,2,3,4,5,6,7,8,9,10); } afterTime = getTimer(); logger.appendText((afterTime-beforeTime) + "\n"); logger.appendText("20,"); beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { a = new Array(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20); } afterTime = getTimer(); logger.appendText((afterTime-beforeTime) + ","); beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { a = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]; } afterTime = getTimer(); logger.appendText((afterTime-beforeTime) + ","); beforeTime = getTimer(); for (i = 0; i < REPS; ++i) { a = createArray(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20); } afterTime = getTimer(); logger.appendText((afterTime-beforeTime) + "\n"); } private function createArray(...rest): Array { return rest; } } }
I then ran the test in this environment:
- Flex SDK (MXMLC) 4.1.0.16076, compiling in release mode (no debugging or verbose stack traces)
- Release version of Flash Player 10.2.154.25
- 2.4 Ghz Intel Core i5
- Mac OS X 10.6.7
Here are the test results I got:
new | [] | var args | |
---|---|---|---|
0 | 241 | 206 | 215 |
5 | 422 | 256 | 274 |
10 | 834 | 318 | 337 |
20 | 1498 | 410 | 426 |
You can see from the table that the []
operator consistently beats the new
operator (constructor) approach. The createArray
/var args method also beats it, but is consistently edged out by the []
operator. However, a graph of the performance as elements increase really shows how badly the constructor version scales:
So we’ve seen that the []
operator is better than the constructor in amount of typing required, bytecode generated, and run-time performance at all lengths. Do keep this in mind if you’re still using Array
, such as in cases where Flash 9 support is still required or you’re just looking for better performance with sorting.
#1 by Matan Uberstein on April 4th, 2011 ·
Thanks for posting :) I did similar Array tests a while ago and came to the same conclusion. Ever since I’ve been using [0,1,2] to construct arrays. Keep up the good work!
#2 by Bob Warfield on April 4th, 2011 ·
Great article, as always.
Your graph is compelling when initializing arrays up front. It would be very useful to understand the case where you have created a large Vector, where is the breakeven point?
In other words, how many elements can I have in a Vector, convert it to an Array purely to use its sort, and then convert back to Vector, and still be ahead?
Presumably, given the O(n) complexity of your typical sort algorithms, you might be ahead most of the time, but it would be great to see an analysis.
Cheers,
BW
#3 by jackson on April 4th, 2011 ·
Thanks Bob. :)
In order to do such a comparison, it would be necessary to know what you’re going to do with the
Vector
other than convert it to and from anArray
for sorting. For example, if you just create aVector
, convert it to anArray
, and convert it back to aVector
, you’ll always be behind because you never used theVector
for its benefits overArray
. For this reason, I think there are actually multiple break-even points as there are multiple things you could be doing with theVector
that are faster than theirArray
equivalents. For the read/write/delete performance, which is not always in favor ofVector
, see my article Flash Player 10.2 Performance.#4 by skyboy on April 5th, 2011 ·
For just plain sorting, you can easily best all of the native methods of Array, no mater which you’re using. The only native sorting method that is mostly unbeatable (but you can get a very close match) is numeric sortOn.
In my library I have a global fastSort function that beats everything except numeric sortOn and very closely matches that, and even manages to beat it if you have multiple elements with the same value (relatively rare). It can sort (or sortOn) any structure that has numeric indicies (Array, Vector, a custom class, Object, Dictionary. Anything you want, really) and a length property: the next update I push for it will extend functionality to allow sorting only portions of objects, rather than the entire thing and remove the need for the passed in object to have a length property.
https://github.com/skyboy/AS3-Utilities/blob/master/skyboy/utils/fastSort.as#L58
#5 by jackson on April 5th, 2011 ·
This is a great contribution to AS3 as
sortOn
performance is really one of the last reasons to useArray
. Others include, unfortunately, Flash APIs requiringArray
, likeDisplayObject.filters
.#6 by as3isolib on April 4th, 2011 ·
I know this has been posted before by you and others, but just as a reminder, for folks who are doing “render pass” or other looping mechanisms, rather than creating a new array, recycle them by calling:
#7 by skyboy on April 6th, 2011 ·
While poking about some things, I remembered another, more obscure, way to create an Array. Var Args.
In the 20 element test I ran, these were my results:
The first result is [], second new, third is a function outside the package, and last is a private function.
#8 by skyboy on April 6th, 2011 ·
I should note, the difference is much more pronounced because I’m not saving a reference to a local variable, and I’m doing multiple operations per loop.
Due to a compiler quirk, I had to use Apparat to initialize the Array via [].
http://pastebin.com/qX7W9gQv
#9 by jackson on April 6th, 2011 ·
This is definitely a third way of creating an
Array
and I have therefore added it to the article along with performance results and chart. My results are similar to yours, only I show this method as slightly slower than the[]
operator. It’s rather sad that it’s so easy to make a better version ofArray
’s own constructor…Thanks for pointing this out!