Este artículo estudia principalmente el contenido relevante de la caché LRU segura de alto rendimiento y hilo, como sigue.
Hace unos años, implementé un caché LRU para encontrar su ID para palabras clave. La estructura de datos es muy interesante porque el rendimiento requerido es lo suficientemente grande como para eliminar los problemas de rendimiento causados por la gran cantidad de locks y palabras clave synchronized . La aplicación se implementa en Java.
Pensé que una serie de asignaciones de referencia atómica mantendría el orden LRU y LRU en ConcurrentHashmap. Al principio, envolví el valor en la entrada. La entrada tiene un nodo en la cadena LRU de la lista de doble enlace. La cola de la cadena mantiene la entrada recientemente utilizada, y el nodo principal almacena la entrada que se puede borrar cuando el caché alcanza un cierto tamaño. Cada nodo apunta a la entrada utilizada para encontrar.
Cuando busca el valor a través de la clave, el caché primero debe buscar el mapa para ver si existe este valor. Si no existe, dependerá del cargador leer el valor de la fuente de datos de forma de lectura y agregarlo en el mapa en el "Agregar si falta". El desafío de garantizar un alto rendimiento es mantener efectivamente la cadena LRU. Este mapa de hash concurrente está segmentado y el nivel de hilo está en un cierto nivel (puede especificar el nivel de concurrencia cuando construye el mapa) no experimentará demasiada competencia de hilos. ¿Pero no puede la cadena LRU dividirse de la misma manera? Para resolver este problema, introduje una cola auxiliar para operaciones de compensación.
Hay seis métodos básicos en caché. Para los golpes de caché, la búsqueda incluye dos operaciones básicas: obtener y ofrecer, y para la pérdida gruesa, hay cuatro métodos básicos: obtener, cargar, poner y ofrecer. En el método PUT, es posible que necesitemos rastrear la operación clara. Cuando el caché golpea, pasivamente hacemos un poco de limpieza en la cadena LRU llamada operación de purificación.
Obtener: entrada de búsqueda en el mapa por clave
Carga: Valor de carga de una fuente de datos
PUT: cree la entrada y asigna a la tecla
Oferta: Agregue un nodo en la cola de la lista LRU que se refiere a una entrada recientemente accedida
Desalto: elimine los nodos en el cabezal de la lista y las entradas asociadas del mapa (después de que el caché alcanza un cierto tamaño)
Purga: eliminar nodos no utilizados en la lista de LRU: nos referimos a estos nodos como agujeros, y la cola de limpieza realiza un seguimiento de estos
La operación de compensación y la operación de purificación son grandes lotes de datos de procesamiento. Echemos un vistazo a los detalles de cada operación.
La operación get funciona de la siguiente manera:
Get (k) -> v Entrada de búsqueda por clave k Si el caché presenta, tenemos una entrada de entrada de la entrada e intenta purgar algunos agujeros de carga de lo más de carga v para la clave k crea entrada e < - (k, v) Intente poner el valor de retorno de la entrada EV EV EV
Si la clave existe, proporcionamos un nuevo nodo en la cola de la cadena LRU para indicar que este es un valor recientemente utilizado. La ejecución de Get and Offer no es una operación atómica (sin bloqueo aquí), por lo que no podemos decir que este nodo ofrece puntos a la entidad más recientemente utilizada, pero definitivamente es la entidad utilizada más recientemente obtenida cuando ejecutamos simultáneamente. No obligamos a obtener y ofrecemos ejecutar el orden entre los subprocesos, ya que esto puede limitar el rendimiento. Después de ofrecer un nodo, intentamos hacer algunas operaciones para borrar y devolver el valor. Echemos un vistazo a las operaciones de oferta y purga en detalle a continuación.
Si se produce pérdida de caché, llamaremos al cargador para cargar valor para esta clave, crear una nueva entidad y ponerla en el mapa, y la operación de poner es la siguiente:
put (e) -> e entrada existente ex < - map.putifabsent (ek, e) si la entrada de oferta ausente e; Si el tamaño alcanza el desalojo de desalentamiento, desaliente algunas entradas, finalización de retorno de finalización, tenemos una entrada existente ex
Como puede ver, puede haber competencia cuando dos o más hilos colocan una entidad en el mapa, pero solo se permite un éxito y se llamará a la oferta. Después de proporcionar un nodo en la cola de la cadena LRU, debemos verificar si el caché ha alcanzado su umbral, que es el identificador que usamos para iniciar la operación de lote. En este escenario de aplicación específico, la configuración del umbral es menor que la capacidad. La operación de limpieza ocurre en un pequeño lote en lugar de cuando se agrega cada entidad. Múltiples subprocesos pueden participar en la operación de compensación hasta que la capacidad de caché alcance su capacidad. El bloqueo es fácil, pero los hilos pueden ser seguros. Limpiar el nodo principal de la cadena LRU requiere eliminación, lo que requiere operaciones atómicas cuidadosas para evitar operaciones de eliminación de múltiples subprocesos en el mapa.
Esta operación de oferta es muy interesante. Siempre trata de crear un nodo, pero no intenta eliminar y eliminar nodos que ya no se usan en la LRU de inmediato.
Oferta (e) Si el nodo de la cola no se refiere a la entrada e asigne el nodo actual c <-en crea un nuevo nodo n (e), nuevos referentes de nodo a la entrada e si el nodo atómico compare y set en, espere c, asigne n nodo n a la cola de la lista de lru si nodo c no nulo
Primero, verificará que el nodo en la cola de la cadena no apunte a la entidad a la que se ha accedido, lo que no es diferente a menos que todos los hilos con frecuencia accedan al mismo par de valor clave. Creará un nuevo nodo en la cola de la cadena. Cuando esta entidad es diferente, antes de proporcionar un nuevo nodo, intenta hacer una comparación y establecer una operación para la entidad, lo que evitará que múltiples hilos hagan lo mismo.
El hilo que asigna con éxito nodos proporciona un nuevo nodo al final de la cadena LRU. Esta operación es la misma que el hallazgo en concurrentlinkedqueue. El algoritmo de dependencia se describe en el siguiente artículo. Algoritmos de cola concurrentes simples, rápidos y prácticos sin bloqueo y bloqueo. El hilo luego verificará si la entidad está relacionada con otros nodos antes. Si es así, el nodo antiguo no se eliminará de inmediato, sino que se marcará como un agujero (la referencia a su entidad se establecerá para vaciar)
Lo anterior es toda la explicación detallada de este artículo sobre el caché LRU seguro de alto rendimiento y hilo, y espero que sea útil para todos. Los amigos interesados pueden continuar referiéndose a otros temas relacionados en este sitio. Si hay alguna deficiencia, deje un mensaje para señalarlo. ¡Gracias amigos por su apoyo para este sitio!