in reply to Re^13: Specializing Functions with Currying
in thread Specializing Functions with Currying

This is closer to what I was doing

#! perl -slw use strict; use Benchmark qw[ cmpthese ]; use List::Util qw[ first ]; our @array = 1 .. 100_000; cmpthese( -1, { func_10th => q[ my $first = first{ length > 3 } @array; # print "F:$first"; ], iter_10th => q[ my $first; for ( @array ) { next unless length > 3; $first = $_; last; } # print "I:$first"; ], func_last => q[ my $first = first{ length > 5 } @array; # print "F:$first"; ], iter_last => q[ my $first; for ( @array ) { next unless length > 5; $first = $_; last; } # print "I:$first"; ], }); __END__ P:\test>381208 Rate func_last iter_last func_10th iter_10th func_last 22.0/s -- -16% -98% -99% iter_last 26.1/s 18% -- -98% -99% func_10th 1196/s 5336% 4488% -- -56% iter_10th 2706/s 12201% 10282% 126% --

Examine what is said, not who speaks.
"Efficiency is intelligent laziness." -David Dunham
"Think for yourself!" - Abigail
"Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon

Replies are listed 'Best First'.
Re^15: Specializing Functions with Currying
by Aristotle (Chancellor) on Aug 09, 2004 at 15:50 UTC

    I prefer not to compare apples and oranges:

    use Benchmark qw[ cmpthese ]; use List::Util qw[ first ]; our @array = 1 .. 100_000; cmpthese( -1, { func_10th => sub { first { length > 3 } @array; }, iter_10th => sub { for ( @array ) { return $_ if length > 3; } }, }); cmpthese( -1, { func_last => sub { first { length > 5 } @array; }, iter_last => sub { for ( @array ) { return $_ if length > 5; } }, }); __END__ Rate func_10th iter_10th func_10th 718/s -- -77% iter_10th 3139/s 337% -- Rate iter_last func_last iter_last 29.4/s -- -29% func_last 41.1/s 40% --

    The results are similar if I run your code though.

    Over here, first always wins given a sufficiently large number of iterations.

    Makeshifts last the longest.

      Strange. Taking your exact code from above and runnning here I get:

      P:\test>type 381208-2.pl #! perl -slw #use strict; use Benchmark qw[ cmpthese ]; use List::Util qw[ first ]; our @array = 1 .. 100_000; cmpthese( -1, { func_10th => sub { first { length > 3 } @array; }, iter_10th => sub { for ( @array ) { return $_ if length > 3; } }, }); cmpthese( -1, { func_last => sub { $_ = first { length > 5 } @array; }, iter_last => sub { for ( @array ) { return $_ if length > 5; } }, }); P:\test>381208-2 Rate func_10th iter_10th func_10th 1196/s -- -61% iter_10th 3076/s 157% -- Rate func_last iter_last func_last 22.6/s -- -23% iter_last 29.3/s 30% --

      Which indicates something about the difference in OS, but I'm not sure what.

      I also wonder what context Benchmark calls the subs in? And is first optimised for the void context case?


      Examine what is said, not who speaks.
      "Efficiency is intelligent laziness." -David Dunham
      "Think for yourself!" - Abigail
      "Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon

        Or differences in compilers and flags used to build the versions.

        $ perl -v | grep ^This This is perl, v5.8.3 built for i486-linux $ perl -V:gccversion gccversion='3.3.2'; $ perl -V:config_args config_args='-de -Dprefix=/usr -Dcccdlflags=-fPIC -Dinstallprefix=/usr + -Doptimize=-O3 -march=i486 -mcpu=i686 -Darchname=i486-linux';

        The relevant bits for call context are in the runloop() function:

        # ... if (ref $c eq 'CODE') { $subcode = "sub { for (1 .. $n) { local \$_; package $pack; &\$c; +} }"; $subref = eval $subcode; } else { $subcode = "sub { for (1 .. $n) { local \$_; package $pack; $c;} } +"; $subref = _doeval($subcode); } # ... &$subref;

        (_doeval is basically a eval.)

        So void context, but I don't think that matters here — the compiler doesn't know the context at the time of eval, so shouldn't be optimizing things away. One would have to instrument the code with a few B::Deparse calls to know for sure, of course. But going by the numbers from the benchmark, it doesn't seem to be making the difference.

        There just seems to be a high startup overhead for first that amortizes over time, given enough time, for at least some Perls.

        Makeshifts last the longest.