Re: [caracas-pm] Re: [l-linux] Variables en perl (era Re:Actualización de distribución y mapa teclado)

Ernesto Hernandez-Novich emhn at telcel.net.ve
Wed Jul 7 16:25:02 CDT 2004


On Wed, 7 Jul 2004, Luis Muñoz wrote:
> El Jul 7, 2004, a las 1:50 PM, Ernesto Hernandez-Novich escribió:
> > Es mucho más eficiente
> >
> > for (1..100) { ... }
> >
> > que
> >
> > for ($i = 1; $i < 100; $i++)
>
> hmmm. Sospecho del señor mostaza, con el candelabro, en la cocina...

Fue Larry, con el peephole optimizator, en Perl 5.6... ;-)

> El operador .. (en Perl 5.x) genera la lista completa _antes_ de que
> for tenga la oportunidad de comenzar a tomar elementos.

...excepto si se usa en for/foreach (man perlop)

"In the current implementation, no temporary array is created when
a 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 this: (...)"

En Perl 5.6 en adelante, el .. utilizado en un for/foreach no genera el
arreglo intermedio.

> El segundo loop, en sintaxis "C", es más eficiente en este contexto
> porque maneja únicamente un escalar y no hay pase de listas de qué
> preocuparse.

Esta es la optimización que se hizo para .. en los for/foreach,
precisamente.

> Verás que si haces algo como
>
>    perl -e 'print 1..1_000_000_000_000, "\n"'
>
> El tamaño de tu instancia de Perl crecerá (y si no te quedas sin
> memoria, posíblemente me dará un ataque de envidia). Eso indica que se
> genera la lista en memoria. Si haces algo como:

Este caso (con tres ceros menos, ver más abajo), seguro, porque no
hay un for...

>    perl -e '$|++; print $_ for 1 .. 1_000_000_000_000'
>
> Verás que el proceso (o tu máquina) muere antes de que se imprima el
> primer número.

Si, muere por "Range iterator outside integer range at -e line 1" :-P

...tres ceros menos más tarde el proceso ejecuta y termina
tranquilamente, ¡y nunca ocupó más de 3Mb de RAM :-)

Nuevamente, la clave es que el .. está en un _for_ que tiene esa
optimización especial.

> En Perl 6.x, la cosa es distinta, porque tiene algo llamado "Lazy
> lists".

Inspiradas en Haskell :-)

> Esas listas flojas, sólo producen elementos cuando algo "se lo
> pide", permitiendo hacer cosas interesantes como por ejemplo:
>
> while (my ($x, $y) = 1 .. Inf)
> {
>    ...
> }

Incidentalmente, eso se puede simular en Perl 5 utilizando clausuras.
Para la próxima reunión llevaré un ejemplo de listas infinitas (streams)
y operaciones sobre conjuntos infinitos.

> De todos modos, aun en ese escenario sospecho que el loop con sintaxis
> "C" debe ser más eficiente.

No. Es más eficiente con la lista, precisamente por la optimización
específica del caso...

#!/usr/bin/perl
use Benchmark;
timethese( 100, {
  'lista' => 'my $i = 0; for (1..1_000_000) { $i++ }',
  'C'     => 'my $i = 0; for (my $j = 1; $j < 1_000_000; $j++) { $i++ }'
                }
	 );

Benchmark: timing 100 iterations of C, lista...
    C: 67 wallclock secs (29.89 usr +  0.05 sys = 29.94 CPU) @ 3.34/s (n=100)
lista: 50 wallclock secs (23.67 usr +  0.04 sys = 23.71 CPU) @ 4.22/s (n=100)
-- 
Ernesto Hernández-Novich - On Linux 2.6.6 i686 - Unix: Live free or die!
Geek by nature, Linux by choice, Debian of course.
If you can't apt-get it, it isn't useful or doesn't exist.
GPG Key Fingerprint = 438C 49A2 A8C7 E7D7 1500 C507 96D6 A3D6 2F4C 85E3



More information about the caracas-pm mailing list