Creo que muchos desarrolladores de Rails no entienden completamente lo que hace la memoria y cómo funciona. Lo he visto aplicado a métodos que devuelven colecciones cargadas de forma diferida (como un conjunto de datos de Sequel) o aplicadas a métodos que no toman argumentos sino que calculan algo en función de las variables de instancia. En el primer caso, la memoria no es más que una sobrecarga, y en el segundo es una fuente de errores desagradables y difíciles de rastrear.
Me no aplico memoization si
- el valor devuelto no es más que un poco caro para el cálculo. Tendría que ser muy caro, y no más optimizable, para que valga la pena la memoria.
- el valor devuelto es o podría ser vago
- el método no es una función pura, es decir, se garantiza que devuelve exactamente el mismo valor para los mismos argumentos, y solo utiliza los argumentos para hacer su trabajo, o otras funciones puras El uso de variables de instancia o métodos de llamada que a su vez usan variables de instancia significa que el método podría devolver resultados diferentes para los mismos argumentos.
También existen otras situaciones en las que la memorización no es apropiada, como la de la pregunta y las respuestas anteriores, pero estas son tres que creo que no son tan obvias.
El último elemento es probablemente el más importante: memoization almacena en caché un resultado basado en los argumentos del método, si el método se parece a esto no se puede memoized:
def unmemoizable1(name)
"%s was here %s" % name, Time.now.strftime('%Y-%m-%d')
end
def unmemoizable2
find_by_shoe_size(@size)
end
Ambos pueden, sin embargo, ser reescrita para tomar ventaja de memoization (aunque en estos dos casos se debe, obviamente, no se puede hacer por otras razones):
def unmemoizable1(name)
memoizable1(name, Time.now.strftime('%Y-%m-%d'))
end
def memoizable1(name, time)
"#{name} was here #{time}"
end
memoize :memoizable1
def unmemoizable2
memoizable2(@size)
end
def memoizable2(size)
find_by_shoe_size(size)
end
memoize :memoizable2
(suponiendo que find_by_shoe_size
no tenían, o confiado en, cualquier efecto secundario)
El truco consiste en extraer una función pura del método y aplicar la memoria a eso en su lugar.
Cuando diga "es decir, se garantiza que devolverá exactamente el mismo valor para los mismos argumentos", ¿cómo se aplicaría eso a las consultas de Rails ActiveRecord? Digamos, por ejemplo, que memoricé un método que recupera todas las ciudades marcadas como activas dentro de un modelo de ciudad, por ejemplo: '' 'def self.active @active_cities = || where ("cities.active = (?)", true) end '' 'Cuando los administradores añaden nuevas ciudades ocasionalmente a la base de datos cuando la aplicación está activa, ¿debería reiniciar el servidor para anular esta variable de instancia memorable? ? ¿O una variable de instancia memorable se destruye y vuelve a crear después de cada solicitud? – Kelseydh
En respuesta a lo anterior: Ahora me doy cuenta de que * la memorización solo persiste una variable de instancia durante el ciclo de vida de ** una sola solicitud. *** Esto es lo que me confundió. Para los principiantes, recomiendo que agregue este punto crítico a su definición. – Kelseydh