in reply to Optimizing Output

I threw together some bizarre benchmarking code to see how much the two methods differ on my machine. The difference was more than I expected... but I pretty much don't believe my results. Code below, once I finish explaining why one should ignore it completely. :)

The old adage is that "Premature optimization is the root of all evil." Yet another true cliche is that 80% of processing is performed in 20% of all code. Optimizing before profiling the code to find out where it's spending time can waste your life away, and lead you to sacrifice readability and maintainability where it isn't necessary to do so.

I second what dws said. I would go a step further, perhaps: write the code in the most readable and maintainable way you can. If one is going to be interpolating enough variables and subroutines that this question becomes worth thinking about, then it's time to consider using a templating system like The Template Toolkit or Text::Template. Many templating systems precompile themselves, so that they are nearly the same speed as either method.

Just for laughs, here's a code snippet that performs a rough-and-ready (read: probably meaningless) comparison of building up a string for appending versus printing a long list:

use strict; use Benchmark qw(cmpthese); use constant NUM_OF_VARS => 10000; use constant NUM_OF_TESTS => 1000; my @names = (); # Meaningless, getting rid of warning *NULL = *NULL; open(NULL, '>/dev/null') or die "Couldn't open /dev/null: $!; stopped" +; ## Initialize a bunch of variables to interpolate { no strict 'refs'; my $var_name = 'aa'; for ( 0 .. NUM_OF_VARS ) { $ {"Q::$var_name" } = "Name is '$var_name', number $_"; push(@names, "\$Q::$var_name"); $var_name++; } } # Build up two subroutine strings to eval my $list_print = "print NULL "; $list_print .= join(",\n", map( qq{'$_ is ', $_, "\\n"}, @names) ); $list_print .= ';'; my $build_print = "my \$string = '';\n"; foreach my $name (@names) { $build_print .= qq{\$string .= '$name is ';\n}; $build_print .= qq{\$string .= $name;\n}; $build_print .= qq{\$string .= "\\n";\n}; } $build_print .= "print NULL \$string;\n"; # Benchmark the subs cmpthese(NUM_OF_TESTS, { 'build_print' => $build_print, 'list_print' => $list_print, });


Update: Forgot to include the code results:

Benchmark: timing 1000 iterations of build_print, list_print... build_print: 120 wallclock secs (119.84 usr + 0.04 sys = 119.88 CPU) +@ 8.34/s (n=1000) list_print: 92 wallclock secs (91.23 usr + 0.11 sys = 91.34 CPU) @ 10 +.95/s (n=1000) Rate build_print list_print build_print 8.34/s -- -24% list_print 10.9/s 31% --

Seems in the expected direction, but I doubt the numbers themselves a great deal.

Replies are listed 'Best First'.
Re: Re: Optimizing Output
by Dogma (Pilgrim) on Apr 15, 2002 at 07:48 UTC
    This was intended to be a question on optimizing outputing of strings. Not when and what to optimize as that's really a different discussion.

    Anyways here are the results of your benchmark on my laptop with linux-2.4.18/perl 5.6.1...

    build_print: 24 wallclock secs (20.87 usr + 0.08 sys = 20.95 CPU) @ 4 +7.73/s (n=1000) list_print: 20 wallclock secs (17.51 usr + 0.01 sys = 17.52 CPU) @ 57 +.08/s (n=1000) Rate build_print list_print build_print 47.7/s -- -16% list_print 57.1/s 20% --
    I suspect there are serous buffering differences from platform to platform.

    Adding "$|++" to the top of the script seems to widen the difference between methods by 1-2%.