2015-10-08 9 views
5

Abbiamo un metodo REST API simile a:Pause RIPOSO chiamate simultanee fino primo completa

List<item> GetItems(int AccountID) 
{ 
    var x = getFromCache(AccountID); 
    if(x==null) 
    { 
     x = getFromDatabase(AccountID); 
     addToCache(AccountID, x); 
    } 
    return x; 
} 

Questo è un metodo abbastanza costoso con alcuni complicato DB chiamate, e abbiamo una situazione comune dove centinaia di utenti lo stesso AccountId effettuerà la chiamata quasi contemporaneamente (vengono tutti notificati con una trasmissione).

Nel metodo, abbiamo memorizzare nella cache il set di risultati per 10 secondi dal momento che un near-time risultato è bene per tutti che effettua la richiesta all'interno di quella finestra. Tuttavia, poiché tutti fanno la chiamata contemporaneamente (di nuovo, per uno specifico ID account) la cache non viene mai compilata in anticipo, quindi tutti finiscono per effettuare la chiamata al database.

Quindi la mia domanda è, all'interno del metodo, come posso mettere in pausa tutte le richieste in arrivo per una specifica AccountID e falli attendere il primo set di risultati per completare, in modo che il resto delle chiamate può utilizzare la cache set di risultati?

Ho letto un po 'di Monitor.Pulse e Monitor.Lock ma l'implementazione di una per-accountid bloccare tipo di mi sfugge. Qualsiasi aiuto sarebbe enormemente apprezzato.

+0

c'è un motivo per cui molti utenti utilizzano la stessa accountid è che un ID account di servizio ..? puoi modificare la tua stored procedure per usare le transazioni o aggiungere un comando 'With No Lock' al lato del database assumendo che tu stia usando Sql Server ..? – MethodMan

+0

vorrei prendere in considerazione una cache di livello 2, quindi se avete un secondo nascondiglio di "attesa" che durano 10 20 secondi, quindi tutte le chiamate che sono attualmente nella cache in attesa si auto blocco e aspettare un po 'prima di provare la vera chiamata db. Analogamente, si potrebbe voler memorizzare nella cache "provato non esiste" per un motivo simile. Eviterei il monitoraggio e il blocco in base al valore delle variabili. Vorrei riservare quei blocchi e sincronizzatori per il codice e la memoria indipendentemente dal valore delle variabili. –

risposta

2

È necessario bloccare sullo stesso oggetto per le richieste con lo stesso accountid ma utilizzare oggetto diverso per ogni individuo accountid. Ecco un esempio di come utilizzare Dizionario per tenere traccia degli oggetti bloccanti per i singoli AccountId.

Dictionary<int, Object> Locks = new Dictionary<int, object>(); 

    List<item> GetItems(int AccountID) 
    { 
     //Get different lock object for each AccountId 
     Object LockForAccountId = GetLockObject(AccountID); 

     //block subsequent threads until first thread fills the cache 
     lock (LockForAccountId) 
     { 
      var x = getFromCache(AccountID); 
      if (x == null) 
      { 
       x = getFromDatabase(AccountID); 
       addToCache(AccountID, x); 
      } 
      return x; 
     } 
    } 

    private Object GetLockObject(int AccountID) 
    { 
     Object LockForAccountId; 

     //we must use global lock while accessing dictionary with locks to prevent multiple different lock objects to be created for the same AccountId 
     lock (Locks) 
     { 
      if (!Locks.TryGetValue(AccountID, out LockForAccountId)) 
      { 
       LockForAccountId = new Object(); 
       Locks[AccountID] = LockForAccountId; 
      } 
     } 
     return LockForAccountId; 
    } 
0

Avete pensato di utilizzare Lazy<T> per questo?

Prova di questo codice:

private object _gate = new object(); 
List<item> GetItems(int AccountID) 
{ 
    lock (_gate) 
    { 
     var x = getFromCache(AccountID); 
     if (x == null) 
     { 
      x = new Lazy<List<item>>(() => getFromDatabase(AccountID)); 
      addToCache(AccountID, x); 
     } 
     return x.Value; 
    } 
} 

Si avrebbe bisogno di cambiare getFromCache & addToCache avere le seguenti firme:

Lazy<List<item>> getFromCache(int AccountID) 
void addToCache(int AccountID, Lazy<List<item>> x) 
Problemi correlati