2013-08-21 22 views
9

Sto scrivendo una libreria di classi portatile che si rivolge a .NET 4.5, app di Windows Store e Windows Phone 8. Ho bisogno di un efficiente meccanismo di cache in memoria, quindi stavo pensando di usare ConcurrentDictionary<K,V>, ma non è disponibile in WP8.Alternativa a ConcurrentDictionary per la libreria di classi portatili

Ci saranno molte letture e relativamente poche scritture, quindi idealmente mi piacerebbe una collezione che supporti letture prive di lock da più thread e che scriva da un singolo thread. Il non-Hashtable non ha questa proprietà, according to MSDN, ma sfortunatamente non è disponibile nel PCL ...

Esiste un'altra classe di raccolta disponibile nel PCL che soddisfi questo requisito? In caso contrario, quale sarebbe un buon modo per ottenere la sicurezza della filettatura senza bloccare le letture? (Blocco in scrittura è OK, dato che non accadrà troppo spesso)


EDIT: grazie alla guida di JaredPar, alla fine ho implementato la cache in modo completamente senza blocchi, utilizzando ImmutableDictionary<TKey, TValue> da Microsoft.Bcl.Immutable:

class Cache<TKey, TValue> 
{ 
    private IImmutableDictionary<TKey, TValue> _cache = ImmutableDictionary.Create<TKey, TValue>(); 

    public TValue GetOrAdd(TKey key, [NotNull] Func<TKey, TValue> valueFactory) 
    { 
     valueFactory.CheckArgumentNull("valueFactory"); 

     TValue newValue = default(TValue); 
     bool newValueCreated = false; 
     while (true) 
     { 
      var oldCache = _cache; 
      TValue value; 
      if (oldCache.TryGetValue(key, out value)) 
       return value; 

      // Value not found; create it if necessary 
      if (!newValueCreated) 
      { 
       newValue = valueFactory(key); 
       newValueCreated = true; 
      } 

      // Add the new value to the cache 
      var newCache = oldCache.Add(key, newValue); 
      if (Interlocked.CompareExchange(ref _cache, newCache, oldCache) == oldCache) 
      { 
       // Cache successfully written 
       return newValue; 
      } 

      // Failed to write the new cache because another thread 
      // already changed it; try again. 
     } 
    } 

    public void Clear() 
    { 
     _cache = _cache.Clear(); 
    } 
} 
+0

Hai mai pensato di scrivere un tipo che avvolgesse un albero immutabile e facesse un CAS per le scritture? Questo ti darebbe le letture senza blocco, la scrittura CAS e potresti semplicemente usare l'albero AVL immutabile di Eric come struttura di supporto http://blogs.msdn.com/b/ericlippert/archive/2008/01/21/immutability-in- c-part-nine-academic-plus-my-avl-tree-implementation.aspx – JaredPar

+0

@JaredPar, che cos'è "CAS"? –

+0

CAS = confronta e scambia. – JaredPar

risposta

4

Un'opzione da considerare è scrivere una facciata sottile su un albero di ricerca immutabile. Ci sono diversi alberi di ricerca immutabili disponibili sul Web tra cui scegliere. Io di solito baso il mio off di Eric Lipperts grande post sul tema

Usando questo come struttura dati di supporto vi darà bloccare gratuito. Le scritture sull'albero possono essere eseguite anche in modalità senza blocco con CAS. Questo sarà un po 'più lento di ConcurrentDictionary perché le ricerche sono O (Log (N)) invece di avvicinarsi a O (1). Ma dovrebbe fare il trucco per te

+0

Ottima soluzione, grazie! Per quanto riguarda le scritture senza blocco, non sono sicuro di come ottenerlo ... se non blocco e ogni thread dello scrittore crea una copia diversa, la seconda sovrascrive quello che ha fatto il primo, non è vero? –

+0

Ecco come sto usando l'albero in questo momento: https://gist.github.com/thomaslevesque/92ad1f8643dfa7a2970a –

+0

@ThomasLevesque dai un'occhiata alle modifiche che ho apportato. Ho provato a spiegare la logica nei commenti https://gist.github.com/jaredpar/20fbdb7ad7fbbb4bd82d – JaredPar

Problemi correlati