Given a simple program:
use strict;
use warnings;
my $count = 0;
foreach ('a' .. 'zzzzzzzzzz') {
$count++;
}
print "$count\n";
Will perl
create entire range of about 1.4+e14
elements in memory and then iterate over them or does it have any internal optimizations to simply step over one state of range operator at a time?
Well, I've actually ran that, so empirical data from top
shows it is the latter (and it didn't finish yet to see data from time
as well), but is it documented anywhere or where to find confirmation for that in sources?
From perldoc perlop:
In the current implementation, no temporary array is created when the range operator is used as the expression in
foreach
loops, but older versions of Perl might burn a lot of memory when you write something like [ what you wrote ]
Yes, the following is optimized into a counting loop:
for (EXPRX..EXPRY) { ... }
perlop mentions this.
In the current implementation, no temporary array is created when the range operator is used as the expression in foreach loops, but [versions of Perl older than 5.6] might burn a lot of memory when you write something like this:
for (1 .. 1_000_000) { # code }
You can see this using the following:
$ perl -e'
my $n = 10_000_000;
system("ps h -o rss $$");
for (1..$n) { system("ps h -o rss $$"); last; }
'
1876
1944
Even within the loop, there's only 1944 KiB used. This is the same amount of that was allocated before the loop, and nowhere near enough to hold 10,000,000 scalars. On the other hand, the following slightly different code shows 385 MiB being used in the loop:
$ perl -e'
my $n = 10_000_000;
system("ps h -o rss $$");
for ((), 1..$n) { system("ps h -o rss $$"); last; }
'
1876
394724
In this latter version, all 10 million scalars are allocated.
In fact, it's not just EXPR..EXPR
that's special. All of the following are implemented differently:
for (EXPR; EXPR; EXPR)
("C-style for loop", an augmented while loop.)for (EXPRX..EXPRY)
(A range and nothing else.)for (reverse CONSTX..CONSTY)
(A constant range, preceded by reverse.)for (reverse EXPRX..EXPRY)
(A variable range, preceded by reverse.)for (@ARRAY)
(An array and nothing else.)for (reverse @ARRAY)
(Reverse of an array and nothing else.)for (reverse LIST)
(Any list that doesn't fit the above patterns.)for (LIST)
(Any list that doesn't fit the above patterns.)Everywhere but in for (CONSTX..CONSTY)
,
CONSTX..CONSTY
is optimized to
my @anon;
BEGIN { @anon = CONSTX..CONSTY; }
@anon
You can see this here:
$ perl -e'
BEGIN { system("ps h -o rss $$"); }
system("ps h -o rss $$");
exit(0);
for (reverse 1..10_000_000) { }
'
1868
709540
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With