2012-05-23 8 views
10

Estoy tratando de implementar un método Cache genérico seguro para subprocesos, y me pregunto cómo debo implementar el bloqueo en él.¿Cómo puedo bloquear con la clave de caché?

Debe tener un aspecto algo como esto:

//private static readonly lockObject = new Object(); 

public T GetCache<T>(string key, Func<T> valueFactory...) 
{ 

    // try to pull from cache here 

    lock (lockObject) // I don't want to use static object lock here because then every time a lock is performed, all cached objects in my site have to wait, regarding of the cache key. 
    { 
    // cache was empty before we got the lock, check again inside the lock 

    // cache is still empty, so retreive the value here 

    // store the value in the cache here 
    } 

    // return the cached value here 

} 
+0

¿Qué estás tratando de lograr? me parece que confundes 2 tipos de bloqueos: bloqueo para garantizar que solo un hilo pueda editar el objeto almacenado en caché y un bloqueo para garantizar que agregar/eliminar del caché sea seguro para los hilos. Agregar un bloqueo por objeto lo ayudará a asegurarse de que solo un hilo pueda cambiarlo, pero no tiene nada que ver con agregarlo/eliminarlo del caché (qué implementación no proporcionó, pero supongo que será algún tipo de diccionario). No creo que puedas descartar el caché, de todos modos, el bloqueo del nivel de recopilación. – YavgenyP

+0

Estoy usando Asp.net caché ... así que no tengo que implementar mi propio diccionario ... Y estoy hablando de bloquear para agregar ... Digamos que 1000 personas solicitaron la página al mismo tiempo, quiero solo uno de ellos para almacenar en caché para objetar, y todos los demás para usarlo ... – Amir

+0

aún necesita bloquear la colección subyacente, y no el objeto. lo que quiere hacer, si lo entiendo correctamente, es verificar si el objeto no está presente en esta colección, y solo luego agréguelo. Si está utilizando .net 4, puede usar una de sus nuevas colecciones de bloqueo, como ConcurrentDictionary para asegurarse de que cada clave se agregue solo una vez. – YavgenyP

Respuesta

1

Este es el caso de que se utiliza el mutex

public T GetCache<T>(string key, Func<T> valueFactory...) 
{ 
    // note here that I use the key as the name of the mutex 
    // also here you need to check that the key have no invalid charater 
    // to used as mutex name. 
    var mut = new Mutex(true, key); 

    try 
    { 
     // Wait until it is safe to enter. 
     mut.WaitOne(); 

     // here you create your cache 
    } 
    finally 
    { 
     // Release the Mutex. 
     mut.ReleaseMutex(); 
    } 
} 
+0

Incluso si necesita un objeto de bloqueo o sincronización de cualquier tipo, ¿por qué debería utilizar mutex y no supervisar? "La clase Mutex usa más recursos del sistema que la clase Monitor" (de [msdn] (http://msdn.microsoft.com/en-us/library/hw29w7t1.aspx)) – YavgenyP

+1

@YavgenyP hay dos razones principales: 1) para bloquear todos los hilos que van a usar/hacer este caché, y solo un hilo. 2) Para dar nombre y bloquear solo esta misma parte de la caché y no todas las caché que se solicitan. - Ahora, no sé si necesita sincronización o no, le reprocho que haga eso y no discuta si lo necesitaba o no. – Aristos

0

El .NET ConcurrentDictionary<TKey, TItem> implementa esto internamente mediante la creación de un bloqueo separado para cada hash clave Esto tiene el beneficio de bloquear solo el hash relevante, incluso al procesar adiciones y eliminaciones de elementos.

1

Acabo de encontrar LazyCache lib. Aunque aún no lo he probado en producción.

IAppCache cache = new CachingService(); 
ComplexObject cachedResults = cache.GetOrAdd("uniqueKey", 
    () => methodThatTakesTimeOrResources()); 
+0

Gracias por el enlace: lo uso en producción y funciona bien, pero creo que diría eso, lo escribí. – alastairtree

Cuestiones relacionadas