Este es el comando perl_performance que se puede ejecutar en el proveedor de alojamiento gratuito de OnWorks utilizando una de nuestras múltiples estaciones de trabajo en línea gratuitas, como Ubuntu Online, Fedora Online, emulador en línea de Windows o emulador en línea de MAC OS.
PROGRAMA:
NOMBRE
makepp_perl_performance - Cómo hacer que Perl sea más rápido
DESCRIPCIÓN
Las mayores ganancias de sintonía generalmente provendrán de mejoras algorítmicas. Pero mientras estos
puede ser difícil de encontrar, también hay muchas cosas que puede hacer mecánicamente.
Makepp es un gran programa de trabajo pesado, donde la velocidad es imprescindible. Se ha puesto mucho esfuerzo
en optimizarlo. Esto documenta algunas cosas generales que hemos encontrado. Actualmente el
Las pruebas concretas que conducen a estos resultados se han descartado en su mayoría, pero planeo
agréguelos gradualmente.
Si está buscando cómo acelerar makepp (más allá de la programación Perl que puso en su
makefiles), mira makepp_speedup. Esta página es completamente independiente de makepp, solo
destinado a poner nuestros resultados a disposición de la comunidad de Perl. Algunas de estas medidas son
sentido común, pero a veces los olvidas. Otros necesitan ser medidos para creerles, así que:
La medida, don't adivinar
Perfil de su programa
Makepp viene con un módulo perfilador.pm en su repositorio de cvs. Esto se ejecuta primero como
programa en una copia (!) de su código, que instrumenta. Luego ejecuta su copia y
obtenga estadísticas configurables por intervalo y un total final de las
funciones llamadas y en la mayor parte del tiempo dedicado a funciones (menos subllamadas). Ambos son
proporcionado absolutamente y en pares llamador-destinatario. (Documentación dentro.)
Esto le indica qué funciones son las candidatas más prometedoras para el ajuste. También
le da una pista de dónde su algoritmo podría estar equivocado, ya sea dentro de sorprendentemente
funciones costosas, o mediante llamadas sorprendentemente frecuentes.
Programa tu solución
Cualquiera de
perl -Mstrict -MBenchmark -we 'my ; timethis -10, sub { }'
tiempo perl -Mstrict -we 'my ; para (0..999_999) { }'
cuando se ejecuta en diferentes variantes de código que pueda imaginar, puede dar resultados sorprendentes.
Incluso las pequeñas modificaciones pueden ser muy importantes. Tenga cuidado de no "medir" el código que pueda
optimizarse, porque descarta el resultado, o porque depende de
constantes.
Dependiendo de su sistema, esto le dirá en kb qué tan gordo se puso Perl:
perl -Mstrict -we ' ; sistema "ps -ovsz $$" '
A continuación, solo mostramos el código dentro de la opción "-e" como una línea.
expresiones regulares
Utilice expresiones regulares simples
Varios partidos combinados con "||" son más rápidos que uno grande con "|".
Usar expresiones regulares precompiladas
En lugar de interpolar cadenas en expresiones regulares (excepto si la cadena nunca cambiará
y usas el modificador "o"), precompila la expresión regular con "qr //" e interpola eso.
Usar (?:...)
Si no usa lo que coincide con la agrupación, no haga que Perl lo guarde con "(...)".
Ancla al comienzo de la cuerda
No haga que Perl mire a través de toda su cadena, si desea una coincidencia solo en el
comenzando.
No anclar al final después de codiciosos
Si tiene un "*" o "+" que coincidirá hasta el final de la cadena, no ponga un "$" después
él.
Utilice tr ///
Esto es dos veces más rápido que s /// cuando es aplicable.
Funciones
Evite la orientación a objetos
La búsqueda de métodos dinámicos es más lenta en cualquier idioma, y Perl, al estar escrito de manera flexible, puede
nunca lo haga en tiempo de compilación. No lo use, a menos que necesite el beneficio de
polimorfismo por herencia. Los siguientes métodos de llamada están ordenados desde el más lento
al más rápido:
$ o-> método (...); # buscado en la clase de $ o y su @ISA
Clase :: método ($ o, ...); # función estática, nueva pila
Clase :: método $ o, ...; # función estática, nueva pila, comprobada en tiempo de compilación
& Class :: método; # función estática, reutilizar pila
Esta última forma siempre es posible si el método (o función normal) no toma argumentos. Si
se necesitan argumentos, tenga cuidado de no proporcionar inadvertidamente ningún opcional
¡unos! Si usa mucho este formulario, es mejor realizar un seguimiento de los mínimos y máximos
número de argumentos que puede tomar cada función. Reutilizar una pila con argumentos adicionales es
no hay problema, serán ignorados.
No modifique la pila
El siguiente pecado se encuentra con frecuencia incluso en el documento Perl:
my $ self = shift;
A menos que tenga una razón pertinente para esto, use esto:
my ($ yo, $ x, $ y, @z) = @_;
Utilice pocas funciones y módulos
Cada función (y eso incluye constantes) ocupa más de 1 kb por su mera
existencia. Dado que cada módulo requiere otros, la mayoría de los cuales nunca necesita, eso
puede sumar. No extraiga un módulo grande, solo para reemplazar dos líneas de código Perl con un
llamada de función de aspecto único más elegante.
Si tiene una función llamada solo en un lugar, y las dos combinadas aún serían
razonablemente cortos, combínelos con los debidos comentarios.
No tenga una función, solo llame a otra con los mismos argumentos. Alias en su lugar:
* alias = \ & función;
Llamadas grupales para imprimir
Las llamadas individuales para imprimir o imprimir con argumentos separados son muy caras. Construir
guarde la cadena en la memoria e imprímala de una vez. Si puede acumular más de 3 kb,
syswrite es más eficiente.
perl -MBenchmark -we 'timethis -10, sub {print STDERR $ _ for 1..5}' 2> / dev / null
perl -MBenchmark -we 'timethis -10, sub {print STDERR 1..5}' 2> / dev / null
perl -MBenchmark -we 'timethis -10, sub {my $ str = ""; $ str. = $ _ para 1..5; imprimir STDERR $ str} '2> / dev / null
Misceláneos
Evita los hashes
Perl se vuelve bastante lento con muchos pequeños hashes. Si no los necesita, use algo
demás. La orientación a objetos funciona igual de bien en una matriz, excepto que los miembros
no se puede acceder por su nombre. Pero puede usar constantes numéricas para nombrar a los miembros.
En aras de la comparabilidad, usamos teclas numéricas simples aquí:
mi $ i = 0; nuestro% a = mapa + ($ i ++, $ _), "a" .. "j"; timethis -10, sub {$ b = $ a {int rand 10}}
nuestro @a = "a" .. "j"; timethis -10, sub {$ b = $ a [rand 10]}
mi $ i = 0; my% a = mapa + ($ i ++, $ _), "a" .. "j"; timethis -10, sub {$ b = $ a {int rand 10}}
my @a = "a" .. "j"; timethis -10, sub {$ b = $ a [rand 10]}
Usar teclas int para conjuntos de referencias
Cuando necesite una representación de referencia única, por ejemplo, para operaciones de conjunto con hashes, use
la forma entera de refs es tres veces más rápida que usar el valor predeterminado bastante impreso
representación de cadena. Advertencia: la variante HP / UX de 64 bits de Perl, al menos hasta
5.8.8 tiene una función "int" con errores, donde esto no funciona de manera confiable. Hay una forma hexadecimal
sigue siendo un poco más rápido que las cadenas predeterminadas. De hecho, esto puede ser incluso más rápido.
que int stringified, dependiendo de la versión o tal vez la configuración de perl. A partir de
5.8.1 también existe el equivalente pero confiable Scalar :: Util :: refaddr
my @list = map {bless {$ _ => 1}, "someclass"} 0..9; mi (% a,% b);
timethis -10, sub {$ a {$ _} = 1 para @list};
timethis -10, sub {$ b {int ()} = 1 para @list};
timethis -10, sub {$ b {sprintf '% x', $ _} = 1 para @list};
timethis -10, sub {$ b {refaddr $ _} = 1 para @list};
También hay sprintf '% p' que supuestamente genera un puntero, pero dependiendo de cuál
expresión conduce a la misma referencia, obtienes diferentes valores, por lo que es inútil.
Cuidado con las cuerdas
Perl es terrible por copiar siempre cadenas, incluso si nunca va a modificar
ellos. Esto desperdicia CPU y memoria. Trate de evitar eso siempre que sea razonablemente posible.
Si la cadena es un parámetro de función y la función tiene una longitud modesta, no copie
la cadena en una variable "my", acceda a ella con $ _ [0] y documente bien la función.
En otros lugares, la función de aliasing de "para (cada uno)" puede ayudar. O simplemente use referencias a
cadenas, que son rápidas de copiar. Si de alguna manera se asegura de que se almacenen las mismas cadenas
solo una vez, puede hacer una comparación numérica para la igualdad.
Evite las operaciones de bits
Si tiene patrones de bits inconexos, puede agregarlos en lugar de agregarlos. Cambiando
se puede realizar mi multiplicación o división entera. Reteniendo solo lo más bajo
los bits se pueden lograr con módulo.
Los miembros hash booleanos separados son más rápidos que rellenar todo en un número entero con
operaciones de bits o en una cadena con "vec".
Usar el orden de las operaciones booleanas
Si solo le importa si una expresión es verdadera o falsa, marque las cosas baratas, como
variables booleanas, primero, y funciones de llamada al final.
Utilice undef en lugar de 0
Ocupa un pequeño porcentaje menos de memoria, al menos como valores hash o de lista. Todavia puedes
consultarlo como booleano.
my% x; $ x {$ _} = 0 para 0..999_999; sistema "ps -ovsz $$"
my% x; undef $ x {$ _} para 0..999_999; sistema "ps -ovsz $$"
mi @x = (0) x 999_999; sistema "ps -ovsz $$"
my @x = (indef) x 999_999; sistema "ps -ovsz $$"
Elija para o mapa
Estos definitivamente no son equivalentes. Dependiendo de su uso (es decir, la lista y el
complejidad de su código), uno u otro puede ser más rápido.
mi @l = 0..99;
para (0..99_999) {mapa $ a = "$ _", @l}
para (0..99_999) {mapa $ a = "$ _", 0..99}
para (0..99_999) {$ a = "$ _" para @l}
para (0..99_999) {$ a = "$ _" para 0..99}
No alias $ _
Si bien es conveniente, es bastante caro, incluso copiar cadenas razonables es
más rápido. El último ejemplo es dos veces más rápido que el primero "para".
my $ x = "abcdefg"; my $ b = 0;
for ("$ x") {$ b = 1 - $ b if / g /} # Copia necesaria solo si se modifica.
para ($ x) {$ b = 1 - $ b si / g /}
local * _ = \ $ x; $ b = 1 - $ b si / g /;
local $ _ = $ x; $ b = 1 - $ b si / g /; # Copiar más barato que el alias.
my $ y = $ x; $ b = 1 - $ b si $ y = ~ / g /;
Utilice perl_performance en línea utilizando los servicios de onworks.net