Var Args Is Slow
Var args (a.k.a. …rest) is a useful feature introduced in AS3. Previously in AS2 (and JavaScript still), we were forced to pass an Array of arguments where an unlimited-length argument list would have been much natural. Unfortunately, this can be really slow. In this article I’ll show a much quicker way to pass unlimited arguments to functions.
Let’s begin with a test program showing three ways to pass unlimited arguments:
package { import flash.display.*; import flash.utils.*; import flash.text.*; /** * An app to show the relative speed of var args (...) to functions taking * an array of "parameters" * @author Jackson Dunstan */ public class MyApp extends Sprite { public function MyApp() { var logger:TextField = new TextField(); logger.autoSize = TextFieldAutoSize.LEFT; addChild(logger); function log(msg:*): void { logger.appendText(msg + "\n"); } const NUM_ITERATIONS:int = 1000000; var i:int; var beforeTime:int; var preAllocatedArgs:Array = []; beforeTime = getTimer(); for (i = 0; i < NUM_ITERATIONS; ++i) { array(preAllocatedArgs); } log("Pre-Allocated Array: " + (getTimer()-beforeTime)); beforeTime = getTimer(); for (i = 0; i < NUM_ITERATIONS; ++i) { array([]); } log("Dynamically-Allocated Array: " + (getTimer()-beforeTime)); beforeTime = getTimer(); for (i = 0; i < NUM_ITERATIONS; ++i) { varArgs(); } log("Var Args: " + (getTimer()-beforeTime)); } private function array(args:Array): int { return args.length; } private function varArgs(...args): int { return args.length; } } }
Above shows three function calls. The first passes an array that was allocated before the test timer began. The second passes an array that is allocated each time the function is called, thereby counting the array allocation. The third passes nothing to a function taking var args. The results are as follows:
Environment | Pre-Allocated Array | Dynamically-Allocated Array | Var Args |
---|---|---|---|
2.2 Ghz Intel Core 2 Duo, 2 GB RAM, Mac OS X | 15 | 397 | 402 |
The dynamically-allocated array and var args are immensely slower than the pre-allocated array! They also turn in just about the same test time, which leads me to believe that var args is nothing more than syntax sugar around a dynamic array allocation and population. Using this knowledge we can design a faster way to pass unlimited arguments: pre-allocate the array and change it as necessary. Changing a couple of elements of one reused array and passing it with every function call is likely to be much faster and much less stressfull on the memory allocator and garbage collector. The var args approach, however clean, does not allow us such an option. We must construct an array with each call of the function using var args.
Now would seem to be a good time to think back to any performance-critical areas of code you’ve written to remember any places where you used var args. If you can think of any, consider revising those areas. If done effectively, you could make those function calls over 20 times faster!
#1 by Jonnie on November 9th, 2009 ·
Looks like I’ll be doing a lot of refactoring this week. Thanks, Jackson… :)
#2 by grapefrukt on November 9th, 2009 ·
Very nice, as usual!
Also, I came to think of this when I read “unlimited arguments” : http://www.youtube.com/watch?v=kQFKtI6gn9Y