Estoy trabajando en una aplicación .NET 4.0, que realiza un cálculo bastante costoso en dos dobles que devuelven un doble. Este cálculo se realiza para cada uno de varios miles de artículos . Estos cálculos se realizan en un Task
subproceso en un subproceso de grupo.
Algunas pruebas preliminares han demostrado que los mismos cálculos se realizan una y otra vez, por lo que me gustaría caché n resultados. Cuando la caché está llena, me gustaría echar a los menos frecuentemente elemento utilizado recientemente. ( Editar: me di cuenta de que con menos frecuencia no tiene sentido, porque cuando el caché está lleno y reemplazaría un resultado por uno recién calculado, ese sería el que se usa con menos frecuencia y se reemplazará de inmediato la próxima vez que se calcule un nuevo resultado y agregado a la caché)
Para implementar esto, estaba pensando en usar un Dictionary<Input, double>
(donde Input
sería una mini-clase que almacena los dos valores dobles de entrada) para almacenar las entradas y los resultados almacenados en caché. Sin embargo, también necesitaría hacer un seguimiento de cuándo se utilizó un resultado la última vez. Para esto, creo que necesitaría una segunda colección que almacenara la información que necesitaría para eliminar un resultado del diccionario cuando el caché se estaba llenando. Me preocupa que mantener esta lista ordenada constantemente impacte negativamente el rendimiento.
¿Hay una manera mejor (es decir, más eficiente) de hacer esto, o tal vez incluso una estructura de datos común que desconozco? ¿Qué tipo de cosas debo perfilar / medir para determinar la optimización de mi solución?
fuente
Esto parece un gran esfuerzo para realizar un solo cálculo dada la potencia de procesamiento que tiene a su disposición en la PC promedio. Además, seguirá teniendo el gasto de la primera llamada a su cálculo para cada par único de valores, por lo que 100,000 pares de valores únicos aún le costarán Tiempo n * 100,000 como mínimo. Tenga en cuenta que el acceso a los valores en su diccionario probablemente será más lento a medida que el diccionario crezca. ¿Puede garantizar que la velocidad de acceso a su diccionario compensará lo suficiente como para proporcionar un rendimiento razonable frente a la velocidad de su cálculo?
De todos modos, parece que probablemente deba considerar encontrar un medio para optimizar su algoritmo. Para esto, necesitará una herramienta de creación de perfiles, como Redgate Ants, para ver dónde están los cuellos de botella y para ayudarlo a determinar si hay formas de reducir algunos de los gastos generales que podría tener en relación con las instancias de clase, los recorridos de listas, la base de datos accesos, o lo que sea que te esté costando tanto tiempo.
fuente
Un pensamiento es por qué solo caché n resultados? Incluso si n es 300,000, solo usaría 7.2MB de memoria (más cualquier extra para la estructura de la tabla). Eso supone tres dobles de 64 bits, por supuesto. Simplemente puede aplicar la memorización a la compleja rutina de cálculo en sí si no le preocupa quedarse sin espacio en la memoria.
fuente
El enfoque con la segunda colección está bien. Debe ser una cola prioritaria que permita encontrar / eliminar valores mínimos rápidamente y también cambiar (aumentar) las prioridades dentro de la cola (la última parte es la difícil, no es compatible con la mayoría de las implementaciones simples de colas prio). La biblioteca C5 tiene tal colección, se llama
IntervalHeap
.O, por supuesto, puedes intentar crear tu propia colección, algo así como a
SortedDictionary<int, List<InputCount>>
. (InputCount
debe ser una clase que combine susInput
datos con suCount
valor)La actualización de esa colección al cambiar el valor de conteo se puede implementar al eliminar y volver a insertar un elemento.
fuente
Como se señaló en la respuesta de Peter Smith, el patrón que está tratando de implementar se llama memorización . En C # es bastante difícil implementar la memorización de manera transparente sin efectos secundarios. El libro de Oliver Sturm sobre programación funcional en C # ofrece una solución (el código está disponible para descargar, capítulo 10).
En F # sería mucho más fácil. Por supuesto, es una gran decisión comenzar a usar otro lenguaje de programación, pero vale la pena considerarlo. Especialmente en cálculos complejos, es probable que haga más cosas más fáciles de programar que la memorización.
fuente