2009-05-21 10 views
5

Para procedimientos en los que ...¿Qué idiomas tienen soporte para el almacenamiento en caché del valor de retorno sin el código repetitivo?

  • existe una estática uno-a-uno entre la entrada y la salida, y
  • el costo de crear el objeto de salida es relativamente alta, y
  • el método se llama repetidamente con la misma entrada

... hay una necesidad de valores de resultado de almacenamiento en caché.

En mi código el siguiente patrón de valor del resultado de almacenamiento en caché se repite mucho (pseudo-código en Java, pero la pregunta es independiente del idioma):

private static Map<Input, Output> fooResultMap = new HashMap<Input, Output>(); 
public getFoo(Input input) { 
    if (fooResultMap.get(input) != null) { 
    return fooResultMap.get(input); 
    } 
    Output output = null; 
    // Some code to obtain the object since we don't have it in the cache. 
    fooResultMap.put(input, output); 
    return output; 
} 

Repitiendo esta estructura todo el tiempo es una violación clara del principio DRY

Idealmente, me gustaría que el código anterior a reducirse a lo siguiente:

@CacheResult 
public getFoo(Input input) { 
    Output output = null; 
    // Some code to obtain the object since we don't have it in the cache. 
    return output; 
} 

Cuando la anotación CacheResult teórica se haría cargo del almacenamiento en caché actualmente estoy haciendo con la mano.

El término general para este tipo de almacenamiento en caché es "memoization".

Un buen ejemplo de la funcionalidad exacta que estoy buscando es Perl core module "Memoize".

¿En qué idiomas existe una solución de almacenamiento en caché similar a Memoize (ya sea en el nivel de idioma o en el nivel de la biblioteca)? En particular, ¿existe una solución de este tipo para cualquier plataforma principal como Java o .NET?

+0

(. Nota, las fugas de código que se muestra y no es seguro para subprocesos) –

+0

Esto se está ejecutando un contexto web, y donde tienes que obtener el valor de Foo de una base de datos cada vez? –

+0

@Chris: No, la pregunta es neutral al contexto. – knorv

Respuesta

4
No

un lenguaje incorporado, poner el módulo CPAN Memoize es bastante popular en Perl tierra, pienso:

# Compute Fibonacci numbers 
    sub fib { 
     my $n = shift; 
     return $n if $n < 2; 
     fib($n-1) + fib($n-2); 
    } 

    use Memoize; 
    memoize('fib'); 
+0

¡Gracias! Esa es una coincidencia exacta, ¡y en realidad es un módulo de Perl central! – knorv

1

Python tiene una serie de recetas de decorador, p. el decorator module, que funciona para esto (if los parámetros son todos inmutables), y tiene implementaciones tanto en JVM como en .NET.

-1
No

una respuesta directa a su pregunta, pero si usted está manteniendo muchas memorias caché, se puede valer la pena usar OSCache (Java) para la administración de esas cachés. El desalojo de objetos obsoletos, etc., se convierte en un problema por el que no debe preocuparse.

Sin embargo, todavía tendría que usar el patrón básico de "comprobación de caché", "retorno en caché" o "crear y agregar a la memoria caché".

+0

Gracias por su respuesta. Soy consciente de OSCache y sus beneficios sobre HashMap, pero el código que proporcioné es solo pseudocódigo para mostrar el mecanismo. No creo que OSCache proporcione ninguna funcionalidad de "memoize". – knorv

-1

Es posible factorizar código como el que en Java, aunque la sintaxis de Java sigue siendo prolijo

private static final Cache<Input, Output> fooCache = Caches.newInstance(
    new Factory<Input, Output>() { public Output create(Input input) { 
     return ... some code ...; 
    }} 
); 
public static Output getFoo(Input input) { 
    return fooCache.get(input); 
} 

Con un mejor soporte sintáctico para las clases internas anónimas, que podría llegar a ser, por ejemplo:

private static final Cache<Input, Output> fooCache = 
    (Input input) (... some code ...); 
public static Output getFoo(Input input) { 
    return fooCache.get(input); 
} 

Esto es algo que la solución AOP puede hacer, a expensas de tener que lidiar con un poco de magia.

+0

Como señalas, todavía es muy detallado. Estoy buscando algo más "Lean à la" memoize "en Perl o Python. – knorv

+0

No lo llamaría * muy * detallado en el esquema de cosas. –

+0

@knorv: la razón por la que no se puede hacer lo que perl/python hace en java es porque en java, las funciones no son ciudadanos de primera clase, por lo que no se puede decorar una función. El proceso de memorización está estrechamente relacionado con el tipo que está almacenando, y ese es el resultado del sistema de tipo en java. no creo que pueda evitarse Un lenguaje que automáticamente "memoizes" para usted es un lenguaje funcional como haskell =) – Chii

0

Puede implementar la anotación @CacheResult en Java, utilizando por ejemplo ASM a transform el método para agregar el código de memoialización.

+0

Esto: http://www.tek271.com/?about=software/java/memoizer/tek271.memoizer.intro.html parece que es en realidad haciendo esto para java –

-1

This question/answer direcciones Memoization in C#. No almacena en caché los resultados, pero podría cambiarse fácilmente para que el mapa sea estático con ReaderWriterLock.

He aquí una muestra de la link given:

public static Func<A, R> Memoize<A, R>(this Func<A, R> f) 
{ 
    var map = new Dictionary<A, R>(); 
    return a => 
    { 
     R value; 
     if (map.TryGetValue(a, out value)) 
     return value; 
     value = f(a); 
     map.Add(a, value); 
     return value; 
    }; 
} 
0

Microsoft T-SQL puede almacenar en caché los valores de retorno de una función CLR en un pr. según consultas ...

(n repetitivo, excepto los atributos correctos en el método al escribir en CLR.)

1

área de incubación de la primavera, springmodules tiene exactamente esta funcionalidad para Java.

Springmodules cache todavía está en el nivel de versión 0.8, pero funcionó bastante bien cuando lo probé el año pasado. Hay opciones para configurar el almacenamiento en caché dentro de los archivos de configuración de primavera, así como con las anotaciones, que se asemeja bastante a su ejemplo. De sus documentos:

public class TigerCacheableService implements CacheableService { 

    @Cacheable(modelId = "testCaching") 
    public final String getName(int index) { 
    // some implementation. 
    } 
... 
} 

Puede elegir la implementación back-end de la memoria caché. Cuando lo estaba probando, obtuve buenos resultados conectándolo a ehcache, que también tiene una buena integración de primavera. Puede configurar declarativamente ehcache para almacenar en caché (en memoria y/o disco) los resultados de los métodos que etiqueta con la anotación @Cacheable.

+0

¿Se puede usar la anotación @Cacheable sin ningún archivo de configuración de Spring? –

Cuestiones relacionadas