FeaturedNOTICIAS

¿Qué es la memorización y por qué es importante? – CloudSavvy IT


código sobre un fondo
whiteMocca / Shutterstock.com

El almacenamiento en caché es una técnica de programación que acelera el rendimiento al almacenar en caché los valores devueltos por costosas llamadas a funciones. Una función «almacenada» generará inmediatamente un valor precalculado si recibe una entrada que ha visto anteriormente.

El almacenamiento en caché es una forma específica de almacenamiento en caché que se presta a escenarios en los que una función costosa se ejecuta repetidamente, a veces con los mismos argumentos. Siempre que la función sea pura para que siempre produzca el mismo valor a partir de un conjunto particular de entradas, almacenarla puede aumentar la eficiencia y reducir los ciclos de CPU desperdiciados.

Con mayor frecuencia encontrará memorización en lenguajes de programación funcionales. Sin embargo, la técnica es de gran utilidad. Es un concepto abstracto que puede incrustar en cualquier código recursivo. Usamos JavaScript para este artículo, pero es posible que desee reescribir los ejemplos en su idioma de trabajo.

Un simple ejemplo

Aquí hay una función simple que genera el factorial de un entero dado:

const factorial = n => {
    if (n === ) return 1;
    else return (factorial(n - 1) * n);
};

El cálculo de factores es recursivo, como factorial() se llama dentro del else condición. El cálculo también es puro, ya que cualquier valor dado de n siempre devolverá el mismo valor. factorial(5) es 120, independientemente del estado del programa.

Debido a la naturaleza recursiva de la función, calcular el factorial de varios números grandes da como resultado operaciones desperdiciadas:

const x = factorial(100);
const y = factorial(50);

Todos los cálculos necesarios para calcular y Ellos eran ya realizado como parte del cálculo de x. Uno mismo factorial() tuvo que almacenar en caché sus entradas y sus correspondientes salidas, el cálculo de y podría acelerarse enormemente.

Almacenar la función factorial

Aquí hay un enfoque básico que almacena el factorial() función:

const cache = {};
 
const factorial = n => {
 
    if (cache[n]) {
        return cache[n];
    }
 
    let value;
    if (n === ) value = 1;
    else value = (factorial(n - 1) * n);
 
    cache[n] = value;
    return value;
 
};

Ahora, hay un cache objetar eso factorial() utilizar para registrar sus valores de salida. Siempre que se llama a la función, primero verifica si ha visto previamente la entrada n. Si es así, puede producirse un cortocircuito inmediatamente y devolver el valor almacenado en caché. De lo contrario, el cálculo recursivo procede normalmente, pero se acelerarán las ejecuciones posteriores que utilicen el mismo número.

Ahora, ciencias de la computación factorial(50) después factorial(100) será mucho más eficiente. El factorial de 50 se calcularía como parte del factorial de 100, por lo que la función podría devolver el valor casi instantáneamente.

Una solución más general

Si bien el código anterior funciona, es específico del factorial() función. Si estuviera utilizando otras funciones similares, tendría que agregar manualmente el código de almacenamiento en caché a cada una de ellas.

Una solución más general le permitiría envolver cualquier función con una función de orden superior que proporcione capacidad de memo:

const memoize = fn => {
 
    const cache = {};
 
    return (...args) => {
        const argsString = JSON.stringify(args);
        if (!cache[argsString]) {
            cache[argsString] = fn(...args);
        }
        return cache[argsString];
    }
 
};

Ahora puedes ajustar el original factorial() función:

const factorial = memoize(n => {
    if (n === ) return 1;
    else return (factorial(n - 1) * n);
});

terminando factorial() con memoize(), adquiere capacidad de almacenamiento automático. La función contenedora devuelve un nuevo función que intercepta todas las llamadas a factorial(), refuerza sus argumentos y comprueba si se han visto antes. Si es así, el valor de retorno anterior se reutiliza sin llamar a la función real en absoluto. Cuando se muestran nuevos argumentos, se invoca la función y su salida se agrega a la caché.

El contenedor utiliza la sintaxis del parámetro rest de JavaScript para aceptar un número variable de argumentos. Esto significa que funcionará con cualquier función de JavaScript. Este enfoque está utilizando JSON.stringify() para crear la representación de cadena de los argumentos, por lo que debe tener cuidado si llama a una función con objetos complejos, que no se pueden representar completamente como JSON.

¿Cuándo no utilizar la memorización?

La memorización puede proporcionar mejoras significativas en el rendimiento, especialmente para operaciones matemáticamente exigentes. Sin embargo, no es una técnica que se utilice en todas partes. No todas las funciones deben almacenarse, ya que en algunos casos puede terminar perjudicando el rendimiento.

Envolviendo una función con memoize(), está forzando una comparación de los argumentos de entrada cada vez que se llama a esa función. Esto en sí mismo consumirá algo de tiempo de CPU. Se ejecuta el contenedor de ejemplo anterior JSON.stringify() cada vez que se llama a la función, se agrega una nueva sobrecarga.

El almacenamiento es apropiado para funciones en las que existe una alta probabilidad de que los mismos valores de entrada se muestren con regularidad. Si rara vez llama a una función con los mismos argumentos, los aciertos de caché serán raros y puede perder rendimiento para la serialización y comparación de argumentos. La retención de la caché también aumenta el uso de la memoria, ya que se deben conservar todas las entradas y salidas anteriores.

Por lo tanto, debe evaluar completamente el papel de cada función en su programa antes de decidir memorizar. Compare el rendimiento con y sin almacenamiento. A veces, puede ser más beneficioso confiar en las optimizaciones del navegador.

Por último, tenga en cuenta que algunas funciones no puedo ser almacenados. La técnica solo funciona con funciones puras: si su función alcanza variables globales o algún otro estado de aplicación, ¡no debería almacenarse!

const functionUsingGlobalState = n => {
    if (n === window.scrollY) return true;
    else return functionUsingGlobalState(n - 1);
}

El almacenamiento de la función anterior puede producir resultados inesperados después de la primera ejecución. Valores de n se almacenará en caché usando el original window.scrollY versión. El contenedor de la nota devolverá la salida en caché, aunque window.scrollY ha cambiado.

Resumen

El almacenamiento en caché es una forma de almacenamiento en caché que acelera el rendimiento de operaciones recursivas repetitivas. Es una técnica de programación funcional que se puede implementar como un contenedor genérico para cualquier función pura.

Muy a menudo encontrará memorización en funciones llamadas con frecuencia que realizan operaciones computacionalmente pesadas. Ayuda a evitar el desperdicio al eliminar la necesidad de volver a calcular los valores que ya se han producido como parte de una llamada anterior.

Los beneficios de memorizar serán menos notables en funciones que son simples al principio o que rara vez se llaman. En algunos casos, el uso inadecuado del almacenamiento puede dañar el rendimiento, así que no almacene a ciegas todas las funciones de su aplicación.

TE INTERESA>>  China supera el recuento de medallas en los Juegos Olímpicos de Tokio - SupChina

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Botón volver arriba