2011-03-16 16 views
5

Tengo singleton que se obtiene de DB, por lo tanto, es una carga costosa. Tiene una carga lenta.Cómo actualizar singleton en C#

Me gustaría crear un método que refresque ese singleton y lo rellene una vez que se requiera.

los datos son DB y muy caros, por lo que quiero actualizarlo solo una vez en caso de que tenga llamadas concurrentes. (Es decir, si consigo 500 llamadas para refrescar, deseo reiniciar la actualización sólo una vez)

public static PageData Instance 
    { 
     get 
     { 
      if (m_Instance == null) 
      { 
       lock (instanceLock) 
       { 
        if (m_Instance == null) 
        { 
         m_Instance = new PageData(); 
        } 
       } 
      } 
      return m_Instance; 
     } 
    } 


public void ReSync() 
     {       
      lock (instanceLock) 
      { 
       /* Setting to null to force the Instance to re-build */ 
       m_Instance = null; 
       PageData pData = Instance; 
      } 
     } 

gracias

+0

¿Cómo debe decidir el sistema cuándo se requiere una actualización? ¿Hay un intervalo de tiempo durante el cual todas las llamadas se deben tratar como la misma? –

Respuesta

2

Esta cifra es ligeramente incorrecto, su

if (m_Instance == null)

debe realmente estar en el interior de la cerradura.

Disculpe, no lo vi.

No hay nada incorporado que pueda hacer que otros clientes abandonen las llamadas en silencio si ya se está refrescando. Los tiempos de espera generarán una excepción, creo. Quizás mantenga un DateTime obsoleto que pueda verificar para evitar hacer la actualización en las llamadas en cola.

+0

¿qué quieres decir? esto es bloqueo de doble comprobación – Himberjack

+0

m_Instance == null puede ser cierto cuando lo comprueba, pero es falso una vez que llega a su bloqueo. Primero debe bloquearlo para asegurarse de que es el único que actúa en m_Instance. –

+0

¡este es un diseño estándar de doble bloqueo de bloqueo! – Himberjack

1

Aparte de la double-checked locking se rompa (corrección, al parecer it does work pero todavía me resulta no especialmente bonita), si tiene acceso de escritura a m_Instance ¿por qué no ponerlo en nueva PageData() en el acto en RESYNC?

+0

Prefiero usar la propiedad encapsulada init – Himberjack

+0

I He visto esto mencionado varias veces, y por lo general vinculando a una página como enlaces de Massif aquí, que se queja de Java. Sin embargo, esta publicación no es sobre Java. No he visto evidencia real de que el bloqueo de doble verificación no funcione en .NET. Me interesaría verlo, si existe. –

+0

@Gabe, la implementación del bloqueo comprobado doble está bien, es solo que todo el patrón está roto, según el enlace. (Investigaciones adicionales encuentran que funciona ahora, pero es probable que se evite: http://stackoverflow.com/questions/394898/double-checked-locking-in-net) – Massif

0

Qué tal si incluye un miembro "lastRefreshed" que también verifica y bloquea durante la actualización. Entonces, si la última actualización ocurrió dentro del tiempo X, ¿no volverá a suceder?

0

Si usted quiere que cumple con el modelo de memoria ECMA, supongo que la aplicación debe ser algo como esto (suponiendo m_Instance no es volátil):

public static PageData Instance 
{ 
    get 
    { 
     PageData instance = Thread.VolatileRead(ref m_Instance); 
     if (instance == null) 
     { 
      lock (instanceLock) 
      { 
       instance = Thread.VolatileRead(ref m_Instance); 
       if (instance == null) 
       { 
        instance = new PageData(); 
        Thread.VolatileWrite(ref m_Instance, instance); 
       } 
      } 
     } 

     return instance; 
    } 
} 

public void ReSync() 
{ 
    /* Setting to null to force the Instance to re-build */ 
    Thread.VolatileWrite(ref m_Instance, null); 
    PageData pData = Instance; 
} 

Si ha definido m_Instance siendo volátil sólo hay una diferencia principal. El m_Instance debe leerse en la variable local antes de realizar la comprobación nula, porque el método ReSync() puede establecer la variable compartida como nula. También eliminé el bloqueo de ReSync() ya que no es realmente necesario. La carrera para inicializar una nueva instancia es segura.

0

Según tengo entendido, ¿espera llamadas simultáneas al método Resync? Esto realmente no debería suceder si lo llamas solo una vez en 500 solicitudes de clientes. Sin embargo, tal vez sea mejor idea no solo bloquear el bloqueo de instancia, porque entonces singleton sería reinstalado varias veces de todos modos, pero no en el "mismo" momento.

public void ReSync() 
{ 
    if (!m_IsResyncing) 
    { 
    lock (m_resyncLock) 
    { 
     if (!m_IsResyncing) 
     { 
     m_IsResyncing = true; 
     Thread.Sleep(100); // sleep for 100ms to accumulate other locks 
     // reinitialize here 
     m_IsResyncing = false; 
     } 
    } 
    } 
} 
1

Según tengo entendido, esto debería funcionar.

Aquí está mi código:

private static instanceLock = new object(); 
private static _refreshing = true; 

public static PageData Instance 
    { 
     get 
     { 
      if (_refreshing) 
      { 
       lock (instanceLock) 
       { 
        if (_refreshing) 
        { 
         m_Instance = new PageData(); 
         _refreshing = false; //now allow next refreshes. 
        } 
       } 
      } 
      return m_Instance; 
     } 
    } 


public void ReSync() 
     { 
      if (!_refreshing)       
       lock (instanceLock) 
       { 
        if (!_refreshing) 
        { 
         _refreshing = true; //don't allow refresh until singleton is called. 
        } 
       } 
     } 
0

puedo necesitar para entender mejor cómo el concurrancy vino a este. Su descripción parece encajar en el alcance del espacio de nombres System.Cashing. Usted dice que el objeto debe almacenar su información por un período de tiempo (algunas opciones están disponibles allí).

Si la siguiente solicitud es la misma que la anterior (usted mismo define los criterios de 'identic'), la persona que llama obtendrá la copia en caché. En realidad, significa que no hay una nueva conexión db. Solo una solicitud de memoria. Si los criterios de caché válidos han pasado, es decir, 30 minutos, la siguiente solicitud se realizará contra la base de datos (durante otro período de tiempo).

Requiere memoria pero es extremadamente rápido y se recomienda en escenarios donde se reutilizan datos.

+0

En términos de refrescante. Cada caché individual se puede restablecer en cualquier momento elegido con un método .Clear() – Independent