johnnywang has asked for the wisdom of the Perl Monks concerning the following question:

There has been some recent discussions about the virtues of map vs. foreach ("advanced" Perl functions and maintainability). The perldoc for map indicates that they are pretty much the same. I did the following comparison in terms of their performance:
use strict; use Benchmark qw(:all); timethese(1000,{ "Foreach" => sub{ my %hash = map{$_=>1} (1..10000);}, "Map" => sub{ my %hash; $hash{$_} = 1 foreach (1..10000);} })
I got the following:
Benchmark: timing 1000 iterations of Foreach, Map... Foreach: 54 wallclock secs (49.54 usr + 0.12 sys = 49.66CPU) @ 20. +14/s (n=1000) Map: 31 wallclock secs (28.80 usr + 0.06 sys = 28.86CPU) @ 34. +65/s (n=1000)
So it seems map is faster, or I'm doing something incorrect?

Note: Oops, as pointed out by ikegami, my Map and Foreach are reversed. I'll leave it as is, so not to confuse the comments. Thanks.

Replies are listed 'Best First'.
Re: performance of map vs. foreach
by ikegami (Patriarch) on Dec 16, 2004 at 00:55 UTC

    Your Foreach test uses map, and your Map test uses foreach. You're making me dizzy. After fixing the test names and running the test for 10 seconds, foreach was 76% faster than map:

    Rate Map Foreach Map 21.9/s -- -43% Foreach 38.6/s 76% --

    Foreach is faster as expected, since foreach doesn't have to build a long list like map does. Update: I wrote a foreach loop that builds an array which is later assigned to %hash. As you can see below, "Map" and "Map-like" have very similar results, as expected.

    use strict; use Benchmark (); Benchmark::cmpthese(-10, { "Map" => sub { my %hash = map{$_=>1} (1..10000); }, "Foreach" => sub { my %hash; $hash{$_} = 1 foreach (1..10000); }, "Map-like" => sub { my @a; push(@a, $_, 1) foreach (1..10000); my %hash = @a; }, }) __END__ Rate Map-like Map Foreach Map-like 21.5/s -- -1% -44% Map 21.8/s 1% -- -43% Foreach 38.6/s 80% 77% --

      The upshot of this is that map and foreach loop just as fast as each other. It's what you ask them to do (and how you use them) that dictates that in some cases one will be faster than the other.


      Dave

Re: performance of map vs. foreach
by brian_d_foy (Abbot) on Dec 16, 2004 at 12:22 UTC
Re: performance of map vs. foreach
by ysth (Canon) on Dec 16, 2004 at 01:30 UTC
    Assuming the goal is just to create the hash keys, you left out:
    "Undef' => sub { my %hash; undef @hash{1..10000}; }
Re: performance of map vs. foreach
by Anonymous Monk on Dec 16, 2004 at 16:56 UTC
    As brian d foy pointed out, you're not doing the same thing. Furthermore, you're using a blocked map, vs a foreach statement modifier. If you want to be fair, you should to the same thing. Below is a benchmark that does the same thing in all cases. It also compares the block form and the expression form. And to top it off, all the cases appear as a coderef, and as a string.
    #!/usr/bin/perl use strict; use warnings; use Benchmark qw /cmpthese/; cmpthese(-1, { m_exp1 => sub {my %hash; map $hash{$_} = 1, 1 .. 10_000}, m_blk1 => sub {my %hash; map {$hash{$_} = 1} 1 .. 10_000}, f_exp1 => sub {my %hash; $hash{$_} = 1 foreach 1 .. 10_000}, f_blk1 => sub {my %hash; foreach (1 .. 10_000) {$hash{$_} = 1}}, m_exp2 => 'my %hash; map $hash{$_} = 1, 1 .. 10_000', m_blk2 => 'my %hash; map {$hash{$_} = 1} 1 .. 10_000', f_exp2 => 'my %hash; $hash{$_} = 1 foreach 1 .. 10_000', f_blk2 => 'my %hash; foreach (1 .. 10_000) {$hash{$_} = 1}', }); __END__ Rate m_blk2 m_exp2 f_blk1 m_exp1 f_blk2 f_exp2 f_exp1 m_blk1 m_blk2 38.0/s -- -5% -7% -9% -10% -10% -13% -14% m_exp2 39.8/s 5% -- -2% -5% -5% -6% -9% -10% f_blk1 40.7/s 7% 2% -- -3% -3% -4% -7% -8% m_exp1 41.9/s 10% 5% 3% -- -0% -1% -4% -5% f_blk2 42.1/s 11% 6% 3% 0% -- -1% -4% -5% f_exp2 42.3/s 11% 6% 4% 1% 1% -- -3% -4% f_exp1 43.8/s 15% 10% 8% 5% 4% 4% -- -1% m_blk1 44.2/s 17% 11% 9% 6% 5% 5% 1% --

    There's no significant difference. Note that the map-block form is both the fastest and the slowest (fastest in the sub form, slowest in the string form, although there's an overhead when calling subs).

    This was done with perl 5.8.6. With older perls, you might find map to be slower.

Re: performance of map vs. foreach
by parv (Parson) on Dec 16, 2004 at 07:24 UTC

    Benchmark could have been more informative if perl version, machine load status and such had been given.

    Using ikegami's code, perl 5.8.5 (FreeBSD/i386, 4.9-p11) gives on a quite idle machine (386MB RAM, 700MHz CPU, FreeBSD 4.10-p5) ...

               Rate Map-like      Map  Foreach
    Map-like 8.69/s       --      -2%     -29%
    Map      8.90/s       2%       --     -27%
    Foreach  12.3/s      41%      38%       --
    

    ... which obviously confirms that overall foreach is indeed faster than map.

      ActivePerl 5.8.0 or 5.8.1, WinXP, P4/2.66GHz, 1GB RAM, idle machine