Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

The Best Infinite Loop

by zdog (Priest)
on Oct 17, 2000 at 02:21 UTC ( #37048=perlmeditation: print w/ replies, xml ) Need Help??

I was doing some coding today when I came to a spot where I needed to use an infinite loop. I remember reading about infinite loops in Programming Perl and that the "for" loop is most customary to use in such a situation. Being the skeptical person that I am, I thought, "It may be customary, but how does it Bench!" So I went and I Benchmarked three infinite loops which I had thought of at the time with this code:
#!/usr/bin/perl -w use strict; use Benchmark; timethese([X], { 'while' => sub { $_ = 0; while (1) { $_++; last if ($_ == 1000); + } }, 'for' => sub { $_ = 0; for (;;) { $_++; last if ($_ == 1000); + } }, 'block' => sub { $_ = 0; { $_++; redo if ($_ < 1000); + } } });

And after running this code with several different iterations (being the scientific person that I am), I came up with the following results:

Benchmark: timing 10000 iterations of block, for, while... block: 8 wallclock secs ( 8.13 usr + 0.00 sys = 8.13 CPU) for: 8 wallclock secs ( 7.90 usr + 0.00 sys = 7.90 CPU) while: 8 wallclock secs ( 8.03 usr + 0.00 sys = 8.03 CPU) Benchmark: timing 20000 iterations of block, for, while... block: 16 wallclock secs (16.25 usr + 0.00 sys = 16.25 CPU) for: 16 wallclock secs (15.80 usr + 0.00 sys = 15.80 CPU) while: 16 wallclock secs (16.08 usr + 0.00 sys = 16.08 CPU) Benchmark: timing 30000 iterations of block, for, while... block: 24 wallclock secs (24.37 usr + 0.00 sys = 24.37 CPU) for: 24 wallclock secs (23.69 usr + 0.00 sys = 23.69 CPU) while: 24 wallclock secs (24.08 usr + 0.00 sys = 24.08 CPU) Benchmark: timing 80000 iterations of block, for, while... block: 66 wallclock secs (65.01 usr + 0.00 sys = 65.01 CPU) for: 63 wallclock secs (63.18 usr + 0.00 sys = 63.18 CPU) while: 64 wallclock secs (64.20 usr + 0.00 sys = 64.20 CPU)

And once again, Programming Perl was absolutely right. The "for" loop was not only the customary infinite loop to use, but also the most efficient infinite loop to use. So now, I have been converted from while (1) { ... } to for (;;) { ... } and hopefully others will soon be converted, too.

Zenon Zabinski | zdog | zdog7@hotmail.com

Update: indigo pointed me in the direction of while() down the thread, and as you can see below, I found that while() was indeed faster than for(;;). Soo....

Comment on The Best Infinite Loop
Select or Download Code
RE: The Best Infinite Loop
by AgentM (Curate) on Oct 17, 2000 at 02:23 UTC
    Nice benchmark. Now, can anyone explain why this is true? P.S. I think it's some sort of anomaly to benchmark an infinite loop, they should both take equally long- forever! Congrats! (just joking, by the way)
    AgentM Systems or Nasca Enterprises is not responsible for the comments made by AgentM- anywhere.
RE: The Best Infinite Loop
by Adam (Vicar) on Oct 17, 2000 at 02:32 UTC
    That's an interesting question... I wonder though if your redo really qualifies as infinite. A more 'proper' loop use of redo might be { $_++; last if ($_ == 1000); redo }
    Also, it appears that you don't know (or more likely forgot) about using a negative $count with timethese() -=- you can make Benchmark run the test for x number of seconds by making $count be -x

    Check out this excellent post on benchmarking for more ideas: Benchmarking Your Code Also, the perldoc for Benchmark.pm has even more good stuff.

RE (tilly) 1: The Best Infinite Loop
by tilly (Archbishop) on Oct 17, 2000 at 04:31 UTC
    Well I was going to reply to this with an amusing anecdote, then I found that the relevant chapter of Code Complete is online. Here is a sample section from this classic on benchmarking.

    The anecdote was that your infinite loop reminded me of the story of a team that was trying to speed up an operating system. Well they profiled and found that it spent most of its time in one loop. So they optimized the heck out of that loop - only to find no reduction in the time spent in that code.

    Turns out that they had optimized the idle loop!

    Oops. :-)

    On an ironic note, I have heard elsewhere that even though they did not speed up the OS, it turned out that they had made it noticably more responsive to users and smoother at multi-tasking. So it turned out to be a good thing to do after all!

RE: The Best Infinite Loop
by indigo (Scribe) on Oct 17, 2000 at 06:01 UTC
    Seems odd, that Perl would supply special while () syntax (while with nothing in the parens), and not make it at least as fast other other comman idioms. Try benchmarking that.
      I never realized that while() could be used as an infinite loop, so I went and benchmarked it up against for (;;) and I got these results:
      Benchmark: timing 20000 iterations of for, while()... for: 45 wallclock secs (43.95 usr + 0.00 sys = 43.95 CPU) @ 45 +5.06/s (n=20000) while(): 43 wallclock secs (43.28 usr + 0.00 sys = 43.28 CPU) @ 46 +2.11/s (n=20000)

      Note: Do not be alarmed if it took longer this time than in the above post, I did it on a slower computer.

      Sooo..., I guess you were right!!

      Zenon Zabinski | zdog | zdog7@hotmail.com

(tye)RE: The Best Infinite Loop
by tye (Cardinal) on Oct 17, 2000 at 10:23 UTC

    I looked at those benchmarks and said, "Well, those all took the same amount of time." Then I read the conclusions drawn and frowned. The numbers are way too close together to determine that any of these are faster than the other. In fact, I'd be surprised if the first two don't compile to the exact same parse tree.

    Compare my benchmarks:

    #!/usr/bin/perl -w use strict; use Benchmark; timethese( 1000, { '0while' => sub { $_ = 0; while (1) { $_++; last if ($_ == 10000 +); } }, '0for' => sub { $_ = 0; for (;;) { $_++; last if ($_ == 10000 +); } }, '0block' => sub { $_ = 0; { $_++; redo if ($_ < 10000) +; } }, '1while' => sub { $_ = 0; while (1) { $_++; last if ($_ == 10000 +); } }, '1for' => sub { $_ = 0; for (;;) { $_++; last if ($_ == 10000 +); } }, '1block' => sub { $_ = 0; { $_++; redo if ($_ < 10000) +; } }, }); __END__ Benchmark: timing 1000 iterations of 0block, 0for, 0while, 1block, 1for, 1while... 0block: 7 wallclock secs ( 6.81 CPU) @ 146.84/s 0for: 7 wallclock secs ( 6.98 CPU) @ 143.27/s 0while: 7 wallclock secs ( 6.70 CPU) @ 149.25/s 1block: 6 wallclock secs ( 6.37 CPU) @ 156.99/s 1for: 6 wallclock secs ( 6.26 CPU) @ 159.74/s 1while: 6 wallclock secs ( 6.32 CPU) @ 158.23/s
    Note that the first time for(;;) is the slowest and the second time it is the fastest.

    I'm sticking with while(1) since I think it looks nicer.

            - tye (but my friends call me "Tye")

      So I tried it (with Deparse)...

      while () { $_++; last if $_ == 1000; } while (1) { $_++; last if $_ == 1000; } for (;;) { $_++; last if $_ == 1000; }
      perl -MO=Deparse test.pl
      for (;;) { ++$_; last if $_ == 1000; } for (;;) { ++$_; last if $_ == 1000; } for (;;) { ++$_; last if $_ == 1000; } test.pl syntax OK

      So they should be all the same speed. I'm with tye on this one - I'll be sticking with with while(1) since I think it looks nicer.

      Have fun,

      rdw

        Those three parse the same, but the block loops don't parse that way. In fact, there are at least three different ways to do an infinite loop with redo that parse differently... So I modified tye's benchmark, and got:
        #!/usr/bin/perl -w use strict; use Benchmark; timethese( 1000, { '0while' => sub { $_ = 0; while (1) { $_++; last if ($_ == 10000) +; } }, '0for' => sub { $_ = 0; for (;;) { $_++; last if ($_ == 10000) +; } }, '0redo1' => sub { $_ = 0; { $_++; redo if ($_ < 10000); + } }, '0redo2' => sub { $_ = 0; { $_++; redo unless ($_ == 10000); + } }, '0redo3' => sub { $_ = 0; { $_++; last if ($_ == 10000); redo +; } }, '1while' => sub { $_ = 0; while (1) { $_++; last if ($_ == 10000) +; } }, '1for' => sub { $_ = 0; for (;;) { $_++; last if ($_ == 10000) +; } }, '1redo1' => sub { $_ = 0; { $_++; redo if ($_ < 10000); + } }, '1redo2' => sub { $_ = 0; { $_++; redo unless ($_ == 10000); + } }, '1redo3' => sub { $_ = 0; { $_++; last if ($_ == 10000); redo +; } }, }); __END__ Benchmark: timing 1000 iterations of 0for, 0redo1, 0redo2, 0redo3, 0wh +ile, 1for, 1redo1, 1redo2, 1redo3, 1while... 0for: 14 wallclock secs (11.43 usr + 0.00 sys = 11.43 CPU) 0redo1: 14 wallclock secs (11.62 usr + 0.00 sys = 11.62 CPU) 0redo2: 15 wallclock secs (12.68 usr + 0.00 sys = 12.68 CPU) 0redo3: 15 wallclock secs (12.36 usr + 0.00 sys = 12.36 CPU) 0while: 14 wallclock secs (11.48 usr + 0.00 sys = 11.48 CPU) 1for: 13 wallclock secs (11.40 usr + 0.00 sys = 11.40 CPU) 1redo1: 14 wallclock secs (11.63 usr + 0.00 sys = 11.63 CPU) 1redo2: 14 wallclock secs (11.54 usr + 0.00 sys = 11.54 CPU) 1redo3: 15 wallclock secs (12.36 usr + 0.01 sys = 12.37 CPU) 1while: 14 wallclock secs (11.42 usr + 0.00 sys = 11.42 CPU)
        I don't know why the difference in times between the first run and the second...
RE: The Best Infinite Loop
by wardk (Deacon) on Oct 17, 2000 at 21:14 UTC

    Shoudn't the least efficient method be the proper one to use over an infinite time? Seems fewer iterations would mean less wear and tear on the loop...

Re: The Best Infinite Loop
by jdhedden (Deacon) on Jun 08, 2005 at 12:32 UTC
    All the differences in timing results presented here (at least for while (), while (1), and for(;;)) are statistically insignificant. The proof for this statement comes from investigating what code is being run in each case. This can be done by using the Perl bytecode compiler (B::Bytecode).

    If you execute the following:

    perl -MO=Bytecode,-H,-ofor_loop -e 'for (;;) {}' perl -MO=Bytecode,-H,-owhile_loop -e 'while () {}' perl -MO=Bytecode,-H,-owhile1_loop -e 'while (1) {}'
    and then diff the resulting files (for_loop, while_loop and while1_loop), you will find that they are all completely identical. This means that all three are exactly equivalent as far as code execution goes. Therefore, which of the three idioms to use is just a matter of personal preference.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlmeditation [id://37048]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others exploiting the Monastery: (6)
As of 2014-10-23 18:05 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    For retirement, I am banking on:










    Results (126 votes), past polls