Try it this way:
#!/usr/bin/perl -w
use Benchmark;
use strict;
use integer;
my %top_hash;
for (my $i = 0; $i < 1000; $i++) {
$top_hash{$i} = $i;
}
sub e {
my $total = 0;
my %hash = %top_hash;
while (my($k, $v) = each %hash) {
$total += $v;
last if $total > 500;
}
}
sub k {
my $total = 0;
my %hash = %top_hash;
foreach my $k (keys %hash) {
my $v = $hash{$k};
$total += $v;
last if $total > 500;
}
}
timethese(500, { 'each' => \&e,
'keys' => \&k });
Why copy the hash? My guess is that there's an internal optimization going on the first time
each is called. If you copy the old hash in every time, that optimization won't take place on the hash you're passing in to both subs.
Of course, you might print out the first ten elements of each and see if they're coming out in the same order. If the first two values you get out of each are both above 250, you'll jump out right there. If it takes a dozen from keys to get over 500, you have to go through the loop six more times. (I don't think that's likely, but it's good to check these kinds of assumptions before benchmarking).
My results for the revised code (500 iterations because copying a 1000-element hash is pretty time consuming):
Benchmark: timing 500 iterations of each, keys...
each: 4 wallclock secs ( 3.77 usr + 0.01 sys = 3.78 CPU)
keys: 5 wallclock secs ( 4.85 usr + 0.00 sys = 4.85 CPU)