cfc generation is slow
|
|
Thread rating:  |
obouillaud - 17 Oct 2007 16:26 GMT Hi
Here is my problem : as soon as I create a cfc, it takes a lot of time (on a computer time scale).
Here is a simple test : On my server it takes between 170 and 200 ms for each loop of hundred cfc generations. That is around 16ms for each CFC... where is the error ??? As soon as I need inheritance or imbricated cfc's for example to display a small list of 5 products on a page, it takes 150-400 ms to generate !!!
Do you have the same behavior ?
<cfloop from="1" to="10" index="j"> <cfset start = GetTickCount()> <cfloop from="1" to="100" index="i"> <cfset "product_#j#_#i#" = CreateObject("component","composants.produits.test")> </cfloop> <cfset looptime = GetTickCount() - start> <cfoutput> #j# : #looptime# ms<br /> </cfoutput> </cfloop>
------------------------------------------------------ and my test.cfc file :
<cfcomponent>
</cfcomponent>
[CJ] - 17 Oct 2007 20:22 GMT component instantiation has always been an expensive process, and not well-suited for doing within a loop.
can't you instantiate it once, then do the assignment inside the loop?
<cfset myComponent = createObject('component', 'com.produits.test') /> <cfloop index="i" ... ><cfset "myVar#i#" = myComponent /></cfloop>
?
Adam Cameron - 17 Oct 2007 20:29 GMT Which version of CF?
 Signature Adam
Grizzly9279 - 17 Oct 2007 21:26 GMT This was a known issue with CF7 at least; rumor has it CF8 was supposed to speed up object instantiation (among other things). Your mileage may vary though.
Like CJ suggested, you may need to re-design your approach to account for performance limitations in this programming environment.
I've gone so far as to implement an "object recycling" mechanism in the past so I could re-use old, discarded CFCs objects, since it was many times faster to do that than to create brand new CFC instances every time.
Like anything, there's more than one way to skin a cat. Sometimes you have to get creative to get the desired result. I know that's not the answer you were looking for, but at least you know that you're not alone in this :)
obouillaud - 18 Oct 2007 08:42 GMT [CJ] : your suggestion is very interresting, that's why I love forums, you can pass 3 days looking for a solution and someone totaly outside of the project finds a solution in a few minutes !
... too bad in the case I have the biggest problem, it's not possible as the instancied object varies. I have a "product" abstract object which is overridden by some "book", "software", ... objects. As I have betwen 10 and 20 different "flavours" of objects, even if I can instanciate them just one time (which is better than on each row), I will still have 10 to 20 x 16ms per page... which is still slow.
I'm working on a caching mechanism to store the objects in the Application scope, it looks promising.
GArlington - 18 Oct 2007 10:03 GMT > [CJ] : your suggestion is very interresting, that's why I love forums, you can > pass 3 days looking for a solution and someone totaly outside of the project [quoted text clipped - 9 lines] > I'm working on a caching mechanism to store the objects in the Application > scope, it looks promising. You can cache the components in session scope (it is safer than application scope), but depending on your component design you can make them application global. I wrote an object caching component some time ago, average request/response time is less than 1 ms. If you want I can share that code and you can work on improving it.
Grizzly9279 - 18 Oct 2007 11:33 GMT CF7 cannot create "copies" of CFCs unfortunately. I can't speak for CF8 though. CF8 was supposed to add support for object serialization however; this leads to me believe that it should be possible in CF8 to "copy" an object, if only by a serialization and de-serialization process.
So in other words, applying the assignment operator to a CFC will always result in a pass-by-reference assignment (a pointer). And no, the duplicate() function does not work as you hope it would against CFCs :)
Best of luck.
cf_dev2 - 18 Oct 2007 16:27 GMT > at the end I have a struct of objects which all refers to the same object, with same properties.
Yes, its important to understand that CF passes most complex objects (structures, queries, cfcs, ..) by reference. You can use Duplicate() on some objects to obtain an independent copy. But as Grizzly9279 mentioned, cfc's are not one of them http://livedocs.adobe.com/coldfusion/7/htmldocs/00001008.htm
obouillaud - 18 Oct 2007 16:45 GMT Ok... I didn't test but I'm quite sure that serialization + duplication + "unserialiszation" is slower than a new CreateObject.
I tried my Application scope cache... and if it seems perfect on my dev server, it seems a bad idea on my production server. The structure in the Application scope rise from a few KB to 10 MB, 15 MB everything seems fine... but after a while the server becomes very slow, unresponsive... with average response time higher than 60 seconds... an I have to restart the server.
Too bad that the caching solution seems worse than the "slow solution"
Adam Cameron - 18 Oct 2007 21:53 GMT > Ok... I didn't test but I'm quite sure that serialization + duplication + > "unserialiszation" is slower than a new CreateObject. Eek, yes.
Did you ever answer my question as to which CF version, btw?
One thing you could look at is - and this is a bit of a cop-out, I agree - is to store the member variables of the object in a cache (so that's just a struct), and use the (cached) CFC instance as a factory sort of arrangement. When you need to do any operations on the object, pass the cached struct in as one of the arguments of the method you're calling. Not very object-oriented, no, but CF ain't OO. Plus it has trouble instantiating objects, so one has to work around this.
 Signature Adam
obouillaud - 19 Oct 2007 08:33 GMT Adam : in my first post is written "I'm running CF8 but it was the same thing on CF7"... That should answer your question :-)
Your suggestion makes me think that in fact it would probably be a better idea to avoid CFC usage. Maybe just cfm pages with includes and functions should be far more efficient !
Adam Cameron - 19 Oct 2007 10:43 GMT > Adam : in my first post is written "I'm running CF8 but it was the same thing > on CF7"... That should answer your question :-) Did you edit the post to include that after the fact? I'm reading from the NNTP feed, and that's not in your first post that I'm looking at.
Either way, sorry for the "silly" question.
I was hoping you were foing to say "CFMX6.0", or something, which was a known dog at instantiating CFCs. CF8's a lot better.
> Your suggestion makes me think that in fact it would probably be a better idea > to avoid CFC usage. Maybe just cfm pages with includes and functions should be > far more efficient ! Yeah, they can be a bit of a pain in the butt performance-wise. It depends on the situation. They're fine for stateless factory type things, or as "bags o' functions", but not much chop as "real" objects, if one's app is going to rely heavily on them.
One thing I think of when I'm looking at your code (which I realise is just an example,but infer it's related to your real situation) though: you're basically generating a collection of products in your loop. So why don't you create ONE collection class, which loads its data from [whatever mechanism your individual products are loaded via]. I guess it depends on whether you're dealing with the collection or with one-off products more often. The collection class could still have a getProduct(sku=something) method.
 Signature Adam
GArlington - 19 Oct 2007 10:36 GMT > Ok... I didn't test but I'm quite sure that serialization + duplication + > "unserialiszation" is slower than a new CreateObject. [quoted text clipped - 7 lines] > > Too bad that the caching solution seems worse than the "slow solution" Your problem may be to do with live server (mis) configuration. I just implemented object caching (currently about 5600 objects cached at 50KB each) AND component caching on per session basis (average 400 concurrent sessions with 20-30 cached components each). It runs on live server with average page response time under 1 second.
obouillaud - 19 Oct 2007 15:25 GMT I edited my first post a few minutes after its initial post... I can't remember why, but I guess it was to add the CF8/CF7 fact... I didn't knew that the newsgroup didn't reflect the changes of the posts. Sorry.
I already use a collection... but it's a collection of "product" objects... ;-(
Adam Cameron - 19 Oct 2007 15:53 GMT > I already use a collection... but it's a collection of "product" objects... ;-( Sure: I'm imagining it's this collection you sample code came from, this being the case. Which would be fine if that notion worked.
What I'm suggesting is not make a "collection of objects"; make a class that is "ObjectCollection", and don't deal with the individual items as objects; deal with ONE object which works @ collection-level, not object-level.
 Signature Adam
obouillaud - 20 Oct 2007 10:44 GMT I understand. and I should store the properties of my products in a struct ? And the methods within the ObjectCollection cfc ?
for example I have a "set_price(float price ,bool with_taxes)" method in my product object. It set both the price with taxes and without taxes (that's an example). So in your suggestion I should rewrite this method with something like : set_price(float price ,bool with_taxes, struct table_of_products,int product_id) which means pass the struct of my products and the id of the product I want to se the price ?
Adam Cameron - 22 Oct 2007 08:57 GMT > I understand. and I should store the properties of my products in a struct ? > And the methods within the ObjectCollection cfc ? Yep.
Note: this is only a suggestion, and something to mull over. I've given it as much thought as it has taken me to type in.
> set_price(float price ,bool with_taxes, struct table_of_products, Well the struct would be one of the member variables of the object, so there's probably no reason to pass it in to the method. It's "safe" to reference member variables directly.
My suggestion of having an external struct holding the data was back when we were discussing having the Product CFC instance as a "bag o' functions" relating to a product struct - which would accordingly only need to be created once, as opposed to a discrete object for each product.
If you're just having the one object for the ProductCollection, then the data should remain in the object.
 Signature Adam
obouillaud - 24 Oct 2007 09:39 GMT That's really lots of work, just to bypass Coldfusion flaws ! They said since CFMX that it's an object oriented language. Everybody is writing about inheritance, design patterns, ... and when you use it... you end up with a slow application, which also seems the cause of server instabilities (cpu/memory intensive) !
Sometimes I think about my firsts CF pages, with includes, and query + output directly in the cfm file... not very good for reusability... but the performances were never a problem !
Adam Cameron - 24 Oct 2007 14:42 GMT > That's really lots of work, just to bypass Coldfusion flaws ! Sure.
> They said since CFMX that it's an object oriented language. No-one that knows what they're talking about has ever claimed that.
It's got some object-oriented touches to it. It ain't OO, and Macromedia / Adobe have never claimed as much.
To be honest, we've had the problems you're seeing in the past, but not for a couple of years. And we use CFCs fairly extensively. Sometimes stuff needs coding around or to be factored in a different way, but as long as one doesn't get too dogmatic about things, there's no probs with that.
 Signature Adam
rupesh_kumar - 30 Oct 2007 11:19 GMT obouillaud, CF8 is much faster than CF7 when it comes to cfc creation. Running your code, my laptop (which is very slow) takes 100 ms for each of iteration. And since you are creating 100 objects in each iteration, thats nearly 1 ms for each CFC which is not that bad. Is it? On a better server machine this time will be much smaller. You can make it even faster by enabling trusted cache.
Regarding cfc, Duplicate does support cfc in CF8. And I think there is some misconception regarding cfc serialization and duplicate. You do not need to worry about serialization and deserialization. All you do is to call Duplicate. But that time will be more or less same as cfc instantiation time.
obouillaud - 30 Oct 2007 12:52 GMT you know what ? I made a miscalculation... 170 ms fo 100 iterations... thats 1.7 ms by iteration, not 17 ms ! That said, I think in fact thats file-system related as when I test on my prouction servers (with files stored on an external NAS), a 100 iterations loop takes between 700 and 1500 ms to complete...
As soon as I enable trusted cache the performances are awesome !!! I will give trusted cache a try...
|
|
|