Thanks for the input, Alex. True, it did take a lot of iterations to get a one second difference, but that's with only one reference to a property. If I had something like: o.foo.bar[3].baz = o.foo.getBaz(), I've suddenly quintupled the number of FindProperty calls. Ditto if I had a few lines of calls, all working off of o.
But mainly I agree that you have to consider whether a given "optimization" is worth it if the code doesn't actually need optimizing and the optimization will make the code harder to understand and maintain. That's why this is such a good tip, since I wanted to use "as" anyway to make the code more maintainable! Good point about SWF/RAM size, though. You finally got me to bother setting up some RSS subscriptions in thunderbird. I always mean to read the various excellent Flex blogs, but never get around to it. Maybe this way I'll be more likely to get those useful nuggets of knowledge. I'm already looking forward to implementing some of your tips on itemRenderers (especially the image centering ones) to try to speed up a particularly painful ADG redraw. On Tue, May 5, 2009 at 12:24 AM, Alex Harui <[email protected]> wrote: > > > I published similar results on my blog a few years back. > > > > The reason it is slower is that there are more byte codes involved and > those byte codes take more time. The more you know, and the more > information you have handy, the less work there is to do and we can make > more assumptions. > > > > For “b.id”, the byte code is more or less: > > Push “id” > > Push “b” > > GetProperty > > > > For “(b as button).id”, the byte code is roughly: > > Push “id” > > Push b > > Push button > > Coerce > > GetProperty > > > > For “o.id”, the byte code is roughly: > > Push “id” > > Push “o” > > FindProperty > > > > and FindProperty is much slower. > > > > Note that it takes 10000000 accesses to feel a 1 second difference. > There’s more byte code involved in using “as” so if you did it everywhere > your SWF will be larger and take up more memory at runtime and could offset > those gains. However, if you’ve got the time, it might be worth doing from > a code maintenance standpoint as the compiler will help you find > misspellings and what not. > > > > > > > > Alex Harui > > Flex SDK Developer > > Adobe Systems Inc. <http://www.adobe.com/> > > Blog: http://blogs.adobe.com/aharui > > > > *From:* [email protected] [mailto:[email protected]] *On > Behalf Of *Pan Troglodytes > *Sent:* Monday, May 04, 2009 7:19 PM > *To:* flexcoders > *Subject:* [flexcoders] for better performance, use "as" rather than just > leaving an object as Object? > > > > > > > I was curious as to the difference between a few different ways of > approaching the situation of an itemRenderer having a "data" property and > deciding whether or not to use "as" to make all the type checking happy. So > I tried some test code and found that it made a big difference whether you > use "as" or just leave the data property as an Object. If you leave it as > an Object, you get a performance hit on the order of 40%+ longer than if you > use "as" to cast it first. > > Here are the ways I tested it. I just decided to pull the "id" property > because it's something that is just a simple access of a private variable, > no complicated stuff. > > var b:Button = new Button; > var o:Object = b; > var s:String; > > s = b.id; > s = (o as Button).id; > s = Button(o).id; > s = UIComponent(o).id; > s = (o as UIComponent).id; > s = o.id; > > I did get a bit fancy and put them in a loop and a timer to isolate each > one. The full code is included below. > > What I found was along the lines of this (give or take a few %): > > Button: 3.16 > Button(): 4.06 129% > as Button: 4.14 131% > UIComponent(): 3.98 126% > as UIComponent: 4.03 128% > Object: 5.38 170% > > I put in the UIComponent ones because sometimes I cast it to a superclass > because I might get several different subclasses passed into a function. > > So what I've found is that if you ignore than noise, the middle four > methods are also approximately the same in timings. But the Object one is > far worse. This probably won't come as any surprise to the Adobe folks or > the people who have been working with Flex a bit more in-depth. I found it > rather useful information, though, considering I'm trying to shave off some > time in various places in one of my apps. Granted, it won't matter as much > outside of loops. > > So many things return the items as objects, such as Arrays/ArrayCollection, > the "data" property of item renderers, etc. I think I'm just going to make > it a habit to put "as" in my code (and not the format of Class(variable) > because sometimes that triggers a function rather than just doing a casting) > all the time. It helps catch errors by doing strict type checking (as long > as you aren't using dynamic classes) and it's a little faster to boot. > > Still, I wish it was as fast as the top line where you don't have to do any > casting/as at all. Any thoughts on that or anything else I've missed? Any > flash insiders want to give your insight on why it works this way under the > hood? > > > <?xml version="1.0" encoding="utf-8"?> > <Application > xmlns="http://www.adobe.com/2006/mxml" > > > <Script> > <![CDATA[ > import mx.core.UIComponent; > > private var timer:Timer = new Timer(100); > private var mode:int = 0; > > private function doClick(e:Event):void > { > if (timer.running) > { > timer.stop(); > timer.removeEventListener(TimerEvent.TIMER, timerClick); > } > else > { > timer.addEventListener(TimerEvent.TIMER, timerClick); > timer.start(); > } > } > > private var last:Number; > private var b:Button = new Button; > private var o:Object = b; > private var s:String; > private var i:int; > private var traceStart:Date; > private var loops:int = 10000000; > private var time:Number; > > private function timerClick(e:Event):void > { > timer.stop(); > > switch(mode) > { > case 0: > trace(); > > traceStart = new Date(); > for (i = 0; i < loops; i++) > s = b.id; > time = (new Date().time - traceStart.time); > trace("Button:\t\t", (time / 1000).toFixed(2)); > last = time; > break; > > case 1: > traceStart = new Date(); > for (i = 0; i < loops; i++) > s = (o as Button).id; > time = (new Date().time - traceStart.time); > trace("as Button:\t", > (time / 1000).toFixed(2), "\t", ((time / last) * > 100).toFixed(0) + "%"); > break; > > case 2: > traceStart = new Date(); > for (i = 0; i < loops; i++) > s = Button(o).id; > time = (new Date().time - traceStart.time); > trace("Button():\t", > (time / 1000).toFixed(2), "\t", ((time / last) * > 100).toFixed(0) + "%"); > break; > > case 3: > traceStart = new Date(); > for (i = 0; i < loops; i++) > s = (o as UIComponent).id; > time = (new Date().time - traceStart.time); > trace("as UIComponent:\t", > (time / 1000).toFixed(2), "\t", ((time / last) * > 100).toFixed(0) + "%"); > break; > > case 4: > traceStart = new Date(); > for (i = 0; i < loops; i++) > s = UIComponent(o).id; > time = (new Date().time - traceStart.time); > trace("UIComponent():\t", > (time / 1000).toFixed(2), "\t", ((time / last) * > 100).toFixed(0) + "%"); > break; > > case 5: > traceStart = new Date(); > for (i = 0; i < loops; i++) > s = o.id; > time = (new Date().time - traceStart.time); > trace("Object:\t\t", > (time / 1000).toFixed(2), "\t", ((time / last) * > 100).toFixed(0) + "%"); > break; > } > > mode = (mode + 1) % 6; > > timer.start(); > } > ]]> > </Script> > <Button click="doClick(event)"/> > </Application> > > > -- > Jason > > > -- Jason

