This content has been marked as final. Show 18 replies
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>
Which version of CF?
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 :)
[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, 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.
EDIT : Hum in fact CJ, I'm not sure of your solution... in my case... in each loop I create the object, I set different properties and then I add it in a struct. So at the end on the loop I have a struct of differents obects (books, softwares, ...). If I try your solution, at the end I have a struct of objects which all refers to the same object, with same properties. I naively though that a
<cfif isdefined("fresh_#product_type#") is false >
<cfset "fresh_#product_type#" = CreateObject("component","composants.produits.#product_type#")>
<cfset my_product = evaluate("fresh_#product_type#")>
would duplicate the object, not create a reference to it...
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.
> 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
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... and I have to restart the server.
Too bad that the caching solution seems worse than the "slow solution"
> Ok... I didn't test but I'm quite sure that serialization + duplication +
> "unserialiszation" is slower than a new CreateObject.
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.
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 : 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)
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... ;-(
> 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
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 ?
> I understand. and I should store the properties of my products in a struct ?
> And the methods within the ObjectCollection cfc ?
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.
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 !
> That's really lots of work, just to bypass Coldfusion flaws !
> 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.
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.
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 that's 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...
And the problem is also more important as soon as you use inheritance.
As soon as I enable trusted cache the performances are awesome !!!
I will give trusted cache a try...