2009-10-08 10 views
8

En una aplicación Delphi en la que estamos trabajando tenemos una gran estructura de objetos relacionados. Algunas de las propiedades de estos objetos tienen valores que se calculan en tiempo de ejecución y estoy buscando una forma de almacenar en caché los resultados para los cálculos más intensivos. Un enfoque que uso es guardar el valor en un miembro privado la primera vez que se calcula. He aquí un breve ejemplo:Enfoques para almacenar en caché los valores calculados

unit Unit1; 

interface 

type 
    TMyObject = class 
    private 
    FObject1, FObject2: TMyOtherObject; 
    FMyCalculatedValue: Integer; 
     function GetMyCalculatedValue: Integer; 
    public 
    property MyCalculatedValue: Integer read GetMyCalculatedValue; 
    end; 

implementation 

    function TMyObject.GetMyCalculatedValue: Integer; 
    begin 
    if FMyCalculatedValue = 0 then 
    begin 
     FMyCalculatedValue := 
     FObject1.OtherCalculatedValue + // This is also calculated 
     FObject2.OtherValue; 
    end; 

    Result := FMyCalculatedValue; 
    end; 

end. 

No es raro que los objetos que se utilizan para el cambio de cálculo y el valor almacenado en caché se deben restablecer y recalculado. Hasta ahora abordamos este problema mediante el uso del patrón de observador: los objetos implementan un evento OnChange para que otros puedan suscribirse, recibir notificaciones cuando cambien y restablecer los valores almacenados en caché. Este enfoque funciona, pero tiene algunas desventajas:

  • Se necesita mucha memoria para gestionar las suscripciones.
  • No escala bien cuando un valor en caché depende de muchos objetos (una lista, por ejemplo).
  • La dependencia no es muy específica (incluso si el valor de caché depende solo de una propiedad, también se restablecerá cuando cambien otras propiedades).
  • Administrar las suscripciones afecta el rendimiento general y es difícil de mantener (los objetos se eliminan, se mueven, ...).
  • No está claro cómo tratar los cálculos en función de otros valores calculados.

Y finalmente la pregunta: ¿puede sugerir otros enfoques para la implementación de los valores calculados en caché?

+0

Incluso si está etiquetado 'delphi', estoy muy interesado en saber si se ha desarrollado un patrón en particular. –

+0

Agregué la etiqueta Delphi para que limite las sugerencias a los lenguajes estáticos y no a los recogidos. – Tihauan

Respuesta

1

En mi trabajo utilizo Negrita para Delphi que puede manejar un número ilimitado de complejas estructuras de los valores almacenados en caché en función de uno al otro. Por lo general, cada variable solo tiene una pequeña parte del problema. En este marco que se llama atributos derivados. Derivado porque el valor no se guarda en la base de datos, solo depende de otros atributos derivados o atributos persistentes en la base de datos.

El código detrás de tal atributo está escrito en Delphi como un procedimiento o en OCL (lenguaje de restricción de objetos) en el modelo. Si lo escribe como código Delphi, debe suscribirse a las variables dependientes. Entonces, si el atributo C depende de A y B, cada vez que A o B cambian, el código de recalc C se invoca automáticamente cuando se lee C. Por lo tanto, la primera vez que se lee C, A y B también se leen (quizás desde la base de datos). Mientras A y B no cambien, puedes leer C y obtener un rendimiento muy rápido. Para cálculos complejos, esto puede ahorrar bastante tiempo de CPU.

La desventaja y la mala noticia es que Bold ya no es compatible oficialmente y tampoco puedes comprarlo. Supongo que puedes obtenerlo si le preguntas a suficientes personas, pero no sé dónde puedes descargarlo. Alrededor de 2005-2006 se pudo descargar gratis de Borland pero ya no. No está listo para D2009 ya que alguien debe portarlo a Unicode.

Otra opción es ECO con dot.net desde Capable Objects. ECO es un complemento en Visual Studio. Es una estructura de soporte que tiene la misma idea y autor que Bold for Delphi. Muchas cosas también se mejoran, por ejemplo, se usa el enlace de datos para los componentes de la GUI. Tanto Bold como ECO usan un modelo como punto central con clases, atributos y enlaces. Esos pueden persistir en una base de datos o un archivo xml. Con la versión gratuita de ECO, el modelo puede tener un máximo de 12 clases, pero, como recuerdo, no hay otros límites.

Bold y ECO contienen mucho más que atributos derivados que lo hacen más productivo y le permiten pensar en el problema en lugar de en los detalles técnicos de la base de datos o en su caso cómo guardar los valores en caché. ¡Sean bienvenidos con más preguntas sobre esos marcos!

Editar: En realidad, hay una descarga link for Embarcadero registred users para Negrita para Delphi para D7, bastante viejo ... Sé que hubo versiones de D2005, D2006 anuncio.

+0

Marcos basados ​​en modelos en general y "Bold for Delphi" en particular suena muy interesante. ¡Gracias! – Tihauan

+0

Encontré Bold for D2006 (creo que es la última versión pública) en uno de mis discos duros, así que si está interesado simplemente envíeme un correo electrónico a [email protected] para que pueda enviarlo. O por Skype, mi id es d98rolb. –

+0

Tihauan, para obtener más información y un pequeño ejemplo de cómo funcionan los valores derivados en Bold, mire mi blog en http://boldfordelphi.blogspot.com/#derattr. –

4

Si desea evitar el patrón Observer, puede intentar utilizar un enfoque hash.

La idea sería que 'hash' los argumentos, y compruebe si esto coincide con el 'hash' para el cual se guarda el estado. Si no lo hace, entonces recalcula (y así guarda el nuevo hash como clave).

Sé que lo hago sonar como si lo hubiera pensado, pero de hecho es utilizado por software bien conocido.

Por ejemplo, SCons (alternativa de Makefile) lo hace para verificar si el objetivo debe reconstruirse de preferencia con un enfoque de marca de tiempo.

Hemos utilizado SCons desde hace más de un año, y nunca hemos detectado ningún problema de destino que no haya sido reconstruido, ¡así que su hash funciona bien!

+0

Solo asegúrese de que calcular el hash (o el método que elija) es (significativamente) más rápido que el recálculo. –

+0

Sí, no lo señalé, ya que sonaba obvio, pero como siempre con optimización ... realmente tiene que medir. –

2

Puede almacenar copias locales de los valores de los objetos externos que sean necesarios. La rutina de acceso luego compara la copia local con el valor externo, y solo hace el recálculo en un cambio.

El acceso a las propiedades de los objetos externos también forzaría una posible reevaluación de esas propiedades, por lo que el sistema debería mantenerse actualizado automáticamente, pero solo volver a calcular cuando sea necesario. No sé si necesita tomar medidas para evitar dependencias circulares.

Esto aumenta la cantidad de espacio que necesita para cada objeto, pero elimina el patrón del observador. También difiere todos los cálculos hasta que se necesiten, en lugar de realizar el cálculo cada vez que cambia un parámetro fuente. Espero que esto sea relevante para su sistema.

unit Unit1; 

interface 

type 
    TMyObject = class 
    private 
    FObject1, FObject2: TMyOtherObject; 
    FObject1Val, FObject2Val: Integer; 
    FMyCalculatedValue: Integer; 
     function GetMyCalculatedValue: Integer; 
    public 
    property MyCalculatedValue: Integer read GetMyCalculatedValue; 
    end; 

implementation 

    function TMyObject.GetMyCalculatedValue: Integer; 
    begin 
    if (FObject1.OtherCalculatedValue <> FObjectVal1) 
    or (FObject2.OtherValue <> FObjectVal2) then 
    begin 
     FMyCalculatedValue := 
     FObject1.OtherCalculatedValue + // This is also calculated 
     FObject2.OtherValue; 
     FObjectVal1 := FObject1.OtherCalculatedValue; 
     FObjectVal2 := Object2.OtherValue; 
    end; 

    Result := FMyCalculatedValue; 
    end; 

end. 
+0

También verificaría que fObject1 y fObject2 estén asignados antes de realizar el cálculo ... solo para estar seguro. – skamradt

+0

@skamradt: de acuerdo. Supuse que la pregunta dejaba fuera la validación de entrada/detección de errores para mantener el código de ejemplo simple. – IanH

Cuestiones relacionadas