2012-07-23 21 views
7

¿Las siguientes suposiciones son válidas para este código? Puse información de fondo debajo del código, pero no creo que sea relevante.Creación de bloqueos dinámicos en tiempo de ejecución en ASP.NET

Supuesto 1: Dado que esta es una sola aplicación, supongo que será manejada por un único proceso. Por lo tanto, las variables estáticas se comparten entre subprocesos y declarar que mi colección de objetos de bloqueo estática es válida.

Supuesto 2: Si sé que el valor ya está en el diccionario, no es necesario que bloquee la lectura. Podría usar un ConcurrentDictionary, pero creo que este estará seguro ya que no estoy enumerando (o borrando), y el valor existirá y no cambiará cuando llamo al UnlockOnValue().

Suposición 3: Puedo bloquear la colección Keys, ya que esa referencia no cambiará, incluso si la estructura de datos subyacente sí lo hace.

private static Dictionary<String,Object> LockList = 
    new Dictionary<string,object>(); 

private void LockOnValue(String queryStringValue) 
{ 
    lock(LockList.Keys) 
    { 
     if(!LockList.Keys.Contains(queryStringValue)) 
     { 
      LockList.Add(screenName,new Object()); 
     } 
     System.Threading.Monitor.Enter(LockList[queryStringValue]); 
    } 
} 

private void UnlockOnValue(String queryStringValue) 
{ 
    System.Threading.Monitor.Exit(LockList[queryStringValue]); 
} 

Entonces me gustaría utilizar este código como:

LockOnValue(Request.QueryString["foo"]) 
//Check cache expiry 
//if expired 
    //Load new values and cache them. 
//else 
    //Load cached values 
UnlockOnValue(Request.QueryString["foo"]) 

Antecedentes: Estoy creando una aplicación en ASP.NET que descarga datos basados ​​en una sola variable definida por el usuario en la consulta cuerda. La cantidad de valores será bastante limitada. Necesito almacenar en caché los resultados para cada valor por un período de tiempo específico.

Approach: Decidí usar archivos locales para almacenar en caché los datos, lo cual no es la mejor opción, pero quería probarlo ya que no es crítico y el rendimiento no es un gran problema. Usé 2 archivos por opción, uno con la fecha de caducidad de la memoria caché y otro con los datos.

Problema: No estoy seguro de cuál es la mejor manera de hacer el bloqueo, y no estoy demasiado familiarizado con problemas de enhebrado en .NET (una de las razones por las que elegí este enfoque). De acuerdo con lo que está disponible, y lo que leo, pensé que lo anterior debería funcionar, pero no estoy seguro y quería una segunda opinión.

+1

¿Cuál es el problema con el uso de 'HttpRuntime.Cache'? – scottm

+0

Esa fue mi primera opción, pero estaba actuando de forma extraña. Puede ser porque mi página borra la respuesta y devuelve un archivo de texto, pero no profundicé demasiado después de encontrarme con problemas similares publicados en Internet, sin respuestas que funcionen para mí. Lo único que no entendí fue la configuración de IIS y si el almacenamiento en caché estaba configurado correctamente. Todavía puedo hacer eso más tarde, pero es un código no crítico y esto planteó preguntas a las que quería respuestas, incluso si no es la mejor arquitectura. – Kendrick

+0

Estoy tratando de implementar una solución muy similar a la tuya en la que estoy almacenando los resultados de los métodos. También necesitaré una forma de crear diferentes bloqueos de caché y me preguntaba si su solución ha resistido la prueba del tiempo, aplausos. –

Respuesta

6

Su solución actual se ve bastante bien. Las dos cosas que cambiaría:

1: UnlockOnValue debe ir en un bloque finally. Si se lanza una excepción, nunca liberará su bloqueo.

2: LockOnValue es algo ineficiente, ya que hace una búsqueda en el diccionario dos veces.Esto no es un gran problema para un diccionario pequeño, pero para uno más grande querrás cambiar a TryGetValue.

Además, su hipótesis 3 es válida, al menos por ahora. Pero el contrato del diccionario no garantiza que la propiedad Keys siempre devuelva el mismo objeto. Y como es muy fácil no confiar en esto, recomendaría no hacerlo. Cada vez que necesito un objeto para cerrar, simplemente creo un objeto para ese único propósito. Algo como:

private static Object _lock = new Object(); 
+0

Debería haber especificado eso en el pseudo código, pero lo tengo en el bloque finally. Nunca pensé en TryGetValue, pero esa es probablemente una mejor opción. El diccionario será pequeño, pero aún así es bueno pensarlo. – Kendrick

+0

Sí, es una de mis preocupaciones ver una llamada a Contiene y luego una llamada a [] ya que ambos tienen que encontrar el elemento. – bmm6o

1

lock tiene un alcance de un solo proceso. Si desea abarcar procesos, tendrá que usar primitivas como Mutex (nombrado).

lock es lo mismo que Monitor.Enter y Monitor.Exit. Si también hace Monitor.Enter y Monitor.Exit, está siendo redundante.

No necesita bloquear en lectura, pero debe bloquear la "transacción" de comprobar si el valor no existe y agregarlo. Si no bloquea esa serie de instrucciones, podría haber algo más entre cuando comprueba la clave y cuando la agrega y la agrega, lo que da como resultado una excepción. El bloqueo que está haciendo es suficiente para hacer eso (no necesita las llamadas adicionales para Entrar y Salir, el bloqueo lo hará por usted).

+0

Supongo que todos los hilos de esta aplicación procederán del mismo proceso. La documentación y los ejemplos que he analizado indican que ese es el caso, aunque todavía no estoy 100% seguro. En realidad, es mi segunda suposición de la que no estoy realmente seguro. Creo que el primero es correcto, y el tercero es probablemente correcto, pero no hay razón para hacer eso simplemente creando un objeto de bloqueo para el diccionario (es decir, podría funcionar, pero probablemente sea un código incorrecto) – Kendrick

+0

Si es una aplicación y todos los hilos son en una sola instancia del proceso, el bloqueo se ajusta a esa situación. –

Cuestiones relacionadas