1) Considere ‘imprimir’ sobre ‘pone’ para fines de rendimiento:
Considere el siguiente código:
require 'benchmark' n = 50_000 Benchmark.bmbm(15) do |r| r.report("original version 2 calls") do for i in 1..n do $stderr.print i, "and" $stderr.puts i end end r.report("single puts call") do for i in 1..n do $stderr.puts "#{i} and #{i}" end end r.report("single print call") do for i in 1..n do $stderr.print "#{i} and #{i}\n" end end end
Cuando ejecuto este script, encontré los siguientes resultados de la evaluación comparativa:
- ¿Cómo comprometen los hackers un sistema protegido por contraseña cuando la velocidad a la que el sistema puede procesar los intentos de inicio de sesión es mucho más lenta que la velocidad a la que se pueden generar combinaciones de contraseña?
- ¿Qué es la explotación de software? ¿Cómo debería uno comenzar a aprenderlo?
- ¿Quora ha sido hackeado alguna vez?
- ¿Qué lenguaje de programación usan los hackers?
- ¿Qué tan difícil es hackear el teléfono celular de alguien si solo conoce su número de teléfono?
akash $ ruby puts_print.rb 2> / dev / null Ensayo ------------------------------------------------- ----------- la versión original 2 llama 0.370000 0.260000 0.630000 (0.639098) Llamadas simples 0.250000 0.140000 0.390000 (0.397769) llamada de impresión única 0.170000 0.070000 0.240000 (0.256804) -------------------------------------------------- - total: 1.260000seg sistema de usuario total real la versión original 2 llama 0.380000 0.270000 0.650000 (0.658632) Llamadas simples 0.240000 0.140000 0.380000 (0.390004) llamada de impresión única 0.170000 0.070000 0.240000 (0.250661)
Los resultados anteriores muestran claramente una mejora en la reducción de llamadas a funciones y en el uso de ‘imprimir’ sobre ‘poner’.
2) Evitar objetos temporales:
Considere seguir el código ruby, ¿cómo podemos hacerlo rápido?
#!/usr/bin/env ruby require 'benchmark' a = "" 1_000_00.times { a += "." }
Si observa la línea de trabajo principal “a + =”. “”, Esta línea se expandirá como
a = a + "."
Lo que significa que cada vez que estamos haciendo esta operación, estamos creando objetos temporales con valor (a + “.”) Y luego asignándolos de nuevo a a. La creación de esta variable temporal nos está costando la mayor parte del tiempo y el espacio. Si podemos evitar el uso de esta variable temporal, podemos hacer las cosas más rápido. Considera lo siguiente:
#!/usr/bin/env ruby require 'benchmark' a = "" 1_000_00.times { a << "." }
El código anterior está haciendo lo mismo que hemos hecho anteriormente, pero se ejecuta mucho más rápido. Si lo perfilamos utilizando benchmark o ruby-prof, podemos ver los beneficios de evitar objetos temporales. A continuación se muestran los resultados de referencia de los 2 enfoques anteriores, observe que el segundo enfoque es casi 100 veces más rápido:
Ensayo --------------------------------------- + = 2.740000 0.460000 3.200000 (3.250396) << 0.040000 0.000000 0.040000 (0.037068) ------------------------------ total: 3.240000seg sistema de usuario total real + = 2.760000 0.510000 3.270000 (3.352737) << 0.040000 0.000000 0.040000 (0.036535)
3) Usar funciones destructivas:
Considere seguir las llamadas a funciones, ¿podemos hacerlo más rápido?
"akashagrawal".gsub "akashagrawal".sub "akash" + "agrawal" [1, 2].collect [1, 2].compact [1, 2].uniq [1 , [2, 3]].flatten [1] + [2]
Todas y cada una de las líneas del código anterior crean un objeto temporal y luego asignan el mismo a ese objeto. Si usamos la versión destructiva correspondiente de arriba (dada a continuación), podemos ahorrar mucho tiempo.
"akashagrawal".gsub! "akashagrawal".sub! "akash" << "agrawal" [1, 2].collect! [1, 2].compact! [1, 2].uniq! [1 , [2, 3]].flatten! [1].concat[2]
Dejo el ejercicio de evaluación comparativa del uso de la función destructiva frente a la no destructiva para los lectores.
No use en exceso las funciones destructivas, ya que “la optimización prematura es la raíz de todo mal”.
4) Iterando: 3 formas como se indica a continuación.
for i in 1..n 1.upto(n) do |i| n.times do |i|
Por lo general, es el más rápido. Pero confíe en sus resultados de evaluación comparativa.
5) coincidencia de cadenas:
Siempre use la combinación de expresiones regulares siempre que sea posible
Peor:
for i in 1..n do File.open(file).each do |line| if line.match('/bin/bash') then $stderr.print line.split(':')[0] $stderr.puts " uses /bin/bash" end end end
Es mejor usar expresiones regulares ya que la coincidencia de cadenas es muy costosa
for i in 1..n do re = /\/bin\/bash/ File.open(file).each do |line| if line.match(re) then $stderr.print line.split(':')[0] $stderr.puts "uses /bin/bash" end end end
Aún mejor porque usar el método de coincidencia es más lento que usar = ~, pero no confíes en mi palabra, perfílalo.
for i in 1..n do File.open(file).each do |line| if line =~ %r{/bin/bash} then $stderr.print #{line.split(':')[0] $stderr.puts "uses /bin/bash" end end
6) hash [“cadena”] vs hash [: símbolo]
hash["my_key_name"] = 1
Esto es realmente muy caro que
hash[:my_key_name] = 1
Cada invocación de “clave” es una asignación de memoria individual. UNA cadena explícitamente para esa variable.
=> cuesta muy poca memoria y tiene aproximadamente el doble de rendimiento que la versión String. La comparación de cadenas es aproximadamente 200-300% tan cara como usar un símbolo. hash[:mykey] = 3
costo de :symbol
costo en la tabla de símbolos global, no se preocupe, a menos que lo abuse. :symbol
7) Concatenación
a = "" 1_000_000.times { a += "." }
es mucho más lento que
a = "" 1_000_000.times { a << "." }
Porque la primera versión usa variables intermedias en cada iteración.
8) Las llamadas al método son caras
Utilizar
if !conditions
o
unless conditions
en lugar de
if conditions.nil?
9) Use tareas paralelas
LENTO:
A = "slide" B = "Share" C = "quora"
RÁPIDO:
A, B, C = "slide", "Share", "quora"
10) Utilice la memorización
Class user attr_accessor :first_name :last_name def full_name @full_name ||= "#{first_name} #{last_name}" end end
11) Elija un entorno inteligente
def foo if env == 'production' #do this else #do that end end
La función anterior verifica ‘env’ cada vez que se llama a la función.
if env == 'production' def foo #do this end else def foo #do that end end
La definición de función anterior guarda esa verificación en cada llamada de función.
12) Escriba el código ‘C’ dentro de ruby usando la gema ‘rubyinline’
Esto es increíble y su código ruby vuela a tiempo. Para obtener más información, visite http://www.rubyinside.com/write-…