Re: Time efficiency of object creation in Perl (or the "bless" function)
by salva (Canon) on Jun 02, 2011 at 09:32 UTC
|
#!/usr/bin/perl
use strict;
use warnings;
use Benchmark qw(cmpthese);
cmpthese(-1, { bless => sub {
my @o;
for (0..1000) {
my $h = { foo => 'bar' };
bless $h, 'Foo';
push @o, $h;
}
},
nobless => sub {
my @o;
for (0..1000) {
my $h = { foo => 'bar' };
push @o, $h;
}
},
bless_scalar => sub {
my @o;
for (0..1000) {
my $s = \(my $t);
bless $s, 'Foo';
push @o, $s;
}
}
}
);
... says ...
Rate bless nobless bless_reuse
bless 575/s -- -32% -39%
nobless 845/s 47% -- -11%
bless_scalar 948/s 65% 12% --
so, the bless operation is pretty cheap.
On the other hand, method calls are quite more expensive that accesing a hash entry. | [reply] [d/l] [select] |
Re: Time efficiency of object creation in Perl (or the "bless" function)
by BrowserUk (Patriarch) on Jun 02, 2011 at 11:33 UTC
|
ended up taking about half a day to run as opposed to the 30 seconds
Given the 144,000% slowdown you've described, I surprised that you need to ask :)
If your processing is cpu-intensive, the simple answer is no. And the more sophisticated the OO, the worse it gets.
If your application is IO-bound--web work; DB work or highly interactive--then you can "get away with it", but for anything requiring real processing with time pressure, you're better off without OO in Perl.
There are ways to mitigate some of the problems you've encountered. For most applications requiring 1000s of entities, those entities tend to group naturally into sets or collections, with the same processing being applied to whole collections rather than individual entities.
If you design your classes such that they represent a complete set of similar entities (stored internally as an array or hash), and the methods process the entire set, or large subsets--ie. you move the loops internal to the methods--then the OO overheads get amortised across large volumes of processing and so become minimal in the overall scheme of things.
This makes a lot of sense in other ways also. It is rare for an application that manipulates 1000s of objects to name them all individually. You almost always end up putting the object refs into arrays in order to loop over them. So, moving the arrays inside the OO and having methods that process the internal array of entities (not objects) either en-masse; or in large range-defined chunks, can yield benefits of clearer code structure at both the caller and internal levels. And that is after all the best reason for using OO.
But OO for its own sake is pointless at best; and if there is a timeliness component to your application spec, something far more detrimental.
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] |
|
|
I think the fact that I first learnt to program in Java has meant that I am perhaps a little too fond of using objects and object methods wherever I can. I think for my purposes the correct thing to do is probably, as you say, use objects as a way of organizing the collections I am processing.
| [reply] |
|
|
I think the fact that I first learnt to program in Java has meant that I am perhaps a little too fond of using objects and object methods wherever I can.
Yes. Enforced habits are hard to break and everything is an object one of the hardest.
One of many nice things about Perl is that it allows you to be judisious with your choices. By using OO at the higher levels of your application, and efficient coding techniques internally to those high level objects, you can get the best of both worlds.
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] |
Re: Time efficiency of object creation in Perl (or the "bless" function)
by CountZero (Bishop) on Jun 02, 2011 at 09:32 UTC
|
Like everything in life: "It depends".Creating and accessing a simple hash will always be faster than creating and using an object. If all you do is to set and get a few fields of an object, then it looks --to me-- that the whole object creation is much overkill. A good example of "good" object oriented programming is DBIx::Class. Sure it is a lot slower than pure DBI, but once you have set-up the database classes for your database, querying the database becomes very easy. Any (run)time lost in using DBIx::Class is paid back many times over in the much shorter development time you now spend to write programs that use that database.
CountZero A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James
| [reply] |
Re: Time efficiency of object creation in Perl (or the "bless" function)
by GrandFather (Saint) on Jun 02, 2011 at 10:26 UTC
|
As salva shows the bless is probably not where the time is. The cost is probably in the method calls. However the a benefit of an object is in added value in methods rather than just wrapping a hash up in a layer of setters and getters. Perl lets you mix and match styles to a very large extent so there need be no particular disincentive to exposing some of the tender underbelly of your objects by allowing direct access to the object's data as a pragmatic solution to a problem.
You can use speedy access to a hash and added value methods to get both the benefits of a hash and the benefits of an object. In fact, after a modest debate with a colleague recently I did exactly that for a class passed out of an API function. The 'public' fields of the object are well documented and are freely accessible by calling code. It helps that there is no interaction between fields and any 'sensitive' data is tucked away in undocumented (therefore notionally 'private') fields. The objects are used to provide access to a database back end and the methods on the object are mostly private functions concerned with translating the data between the public form for calling code and the form required by the database. Thus cheap and easy access to data fields and nice encapsulation of the database facing code.
True laziness is hard work
| [reply] |
Re: Time efficiency of object creation in Perl (or the "bless" function)
by armstd (Friar) on Jun 02, 2011 at 14:50 UTC
|
Your use model is not entirely clear from your post, so I can only speak from personal experience where I have had issues with method call performance across a large number of objects as well.
For this sort of thing, if I were using objects, I would likely adopt a slightly different design. The design you describe seems to be a simple data-driven design. Consider instead a responsibility driven approach.
My own responsibility driven solution was to incorporate "Set" container objects, composed of one or more "Data" objects. I implement most computation logic in the Set objects, and Data objects only contain data attributes, providing accessors. The Set classes inherit generic Set/aggregation functions from a base class for consistency, but function as "friend" classes of the specific Data classes. In my design, a "Car" object would be contained by a "CarSet". Treating "CarSet" as a friend class in my design allows/expects it to access the internal structure (hash) of "Car" directly, rather than through Car's accessor methods, which is what any non-friend class is limited to. Responsibilities between the Set and Data objects are very clearly defined, providing loose coupling, but the overall design is still very cohesive.
This structure allows (and hopefully influences) developers to optimize computation (or I/O) performance for multiple objects simultaneously, rather than individually. Individual objects can still be dealt with as an "army of one", constructing a Set on the fly to access computation/io methods. The structure also encourages development of reusable computation/io methods, driving that logic into objects as well, specifically objects that have special performance-by-design contracts with my data objects.
You can have objects and still have performance, but your design must accommodate performance requirements.
| [reply] |
Re: Time efficiency of object creation in Perl (or the "bless" function)
by GrandFather (Saint) on Jun 02, 2011 at 21:15 UTC
|
You have a benchmark showing very little cost for blessing objects, but the actual cost of a simple getter compared with a hash access may be the thing of concern. Well, probably it isn't. It certainly isn't the more than 144,000% hit others have suggested. The following benchmark result indicates at worst a factor of five cost between a getter and a hash access used in a simple assignment:
Rate derived baseobj hash
derived 1641/s -- -0% -79%
baseobj 1649/s 0% -- -79%
hash 7876/s 380% 378% --
True laziness is hard work
| [reply] [d/l] [select] |
Re: Time efficiency of object creation in Perl (or the "bless" function)
by locked_user sundialsvc4 (Abbot) on Jun 02, 2011 at 14:36 UTC
|
If you are seeing “30 seconds” turning into “half a day,” then there can be only one plausible explanation: your system is thrashing.
Thrashing causes an exponential degradation in performance ... what’s known as “hitting the wall.”
| |
|
|
| [reply] |
|
|
To clarify a little: I have tab-delimited files that usually end up being around half a million lines long each. Originally, I had set my code up so that it would create a new object for each line, where its "fields" were the attributes. This took "half a day", or to be less colloquial about 4 hours. Now, I'm just parsing each line as a hash of attributes into a set of hashes that stores all the lines have their type attributes in common. This is now taking 16 seconds.
I don't think my system is thrashing. I just haven't quite learnt how to use Perl effectively!
| [reply] |
|
|