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....
(tye)RE: The Best Infinite Loop
by tye (Sage) 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") | [reply] [d/l] [select] |
|
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
| [reply] [d/l] [select] |
|
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...
| [reply] [d/l] |
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! | [reply] |
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.
| [reply] |
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. | [reply] |
|
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
| [reply] [d/l] [select] |
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...
| [reply] |
Re: The Best Infinite Loop
by jdhedden (Deacon) on Jun 08, 2005 at 12:32 UTC
|
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. | [reply] [d/l] |
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)
| [reply] |
|
|