Timothy Kimball ([EMAIL PROTECTED]) wrote:
> 
> : Because someone (and with apologies to all, I don't recall off the top
> : of my head who)correctly pointed out to me earlier in this thread that
> : using map() here was inefficient. map() builds and returns an array, so
> : there's no point in using it in this void context. Aside from that,
> : both do the same thing. The postfix for is cleaner. =o)
> 
> I agree that the postfix is cleaner, but when I benchmark these, map
> looks faster- though several months ago, map was slower (IIRC). Maybe
> something changed in 5.6.0 to make map faster in a null context...?
> 
> Here's the script & output (Perl 5.6.0 on an Ultra 10):

Whoa!  It was me who noted that the map should be avoided in void
context, but trying your benchmark, I had the same results.  However,
since I did some benchmarks on my own *before* stating that map should
not be used, I had some completely different results.

I was suspicious, since your results are by far too fast - an U10 is not
that much of a big machine, isn't it?  ;-)

...hack, hack, hack...

Ah, a Heisenbug.  There's a problem with your benchmarking:

---------- snip ----------
my @lines = qw(
...
timethese(500_000,{
            "1. map    " => 'map { s/a// } @lines',
---------- snip ----------

Inside 'timethese', @lines is unknown and thus empty.  Looks as if the
Benchmark module ignores '$@' after the eval, but I haven't checked for
that.  But fact is, you're running 500_000 loops on en empty list, and
map doesn't need to create any new list at all - well, at least it looks
as if map is *pretty* fast on empty lists.

There are 2 modifications required in your benchmark:

    a. make the @list array global, so it's visible inside 'timethese'

    b. make sure the s/ doesn't truncate the string, so there's still
       some work to do after 10 test loops. (I did that by replacing s/
       with a switching tr...)

(
    c. as a not really necessary addon I decided to create more random
       test data (yes, I *am* using nested maps there >:-> ).
)

Here's my version of your benchmark:

    ---------- snip ----------
    kanku-dai:~$ cat check.pl
    #!/usr/bin/perl -w

    use strict;
    use Benchmark;
    use vars qw{@lines};

    my @chars=('A'..'Z', 'a'..'z', 0 .. 9, ' ');
    @lines=map { join('', @chars[map { rand @chars } (0 .. 63)]) } (1 .. 10);

    timethese(500_000,{
        "1. map    " => 'map { tr/abAB/baBA/ } @lines',
        "2. foreach" => 'foreach ( @lines ) { tr/abAB/baBA/ }',
        "3. for    " => 'tr/abAB/baBA/ for @lines',
    });
    ---------- snip ----------

Here are the new results:

    ---------- new ----------
    kanku-dai:~$ perl check.pl
    Benchmark: timing 500000 iterations of 1. map    , 2. foreach, 3. for    ...
    1. map    :  7 wallclock secs ( 6.95 usr +  0.01 sys =  6.96 CPU) @ 71839.08/s 
(n=500000)
    2. foreach:  9 wallclock secs ( 8.38 usr +  0.01 sys =  8.39 CPU) @ 59594.76/s 
(n=500000)
    3. for    :  9 wallclock secs ( 8.13 usr +  0.01 sys =  8.14 CPU) @ 61425.06/s 
(n=500000)
    kanku-dai:~$ 
    ---------- new ----------

So, it looks as if you're right, map *IS* a bit faster on small data
sets, but not in the dimensions that your benchmark suggested.
Increasing the amount of data makes that difference go away however.
Here's the data for 500 benchmark loops over 10_000 lines of data:

    ---------- mod_new ----------
    kanku-dai:~$ perl check.pl
    Benchmark: timing 500 iterations of 1. map    , 2. foreach, 3. for    ...
    1. map    : 10 wallclock secs ( 9.71 usr +  0.04 sys =  9.75 CPU) @ 51.28/s (n=500)
    2. foreach:  9 wallclock secs ( 9.58 usr +  0.01 sys =  9.59 CPU) @ 52.14/s (n=500)
    3. for    :  9 wallclock secs ( 9.44 usr +  0.02 sys =  9.46 CPU) @ 52.85/s (n=500)
    kanku-dai:~$ 
    ---------- mod_new ----------

Conclusion:  The perlfaq6 information seems outdated, so the only
argument against map is the question of style, readability and personal
taste - naturally, I stick with my style ;-)

Mike

-- 
                     If we fail, we will lose the war.

Michael Lamertz          | [EMAIL PROTECTED] / [EMAIL PROTECTED]
    Nordstr. 49          | http://www.lamertz.net
    50733 Cologne        | Work: +49 221 3091-121
    Germany              | Priv: +49 221 445420 / +49 171 6900 310

Reply via email to