2013-08-21 15 views
9

Ich schreibe eine portable Klassenbibliothek, die auf .NET 4.5, Windows Store-Apps und Windows Phone 8 abzielt. Ich brauche einen effizienten In-Memory-Cache-Mechanismus, also habe ich über die Verwendung von ConcurrentDictionary<K,V> nachgedacht. aber es ist nicht in WP8 verfügbar.Alternative zu ConcurrentDictionary für portable Klassenbibliothek

Es wird viele Lesevorgänge und relativ wenige Schreibvorgänge geben. Daher möchte ich idealerweise eine Sammlung, die blockierungsfreie Lesevorgänge aus mehreren Threads unterstützt und nach einem einzelnen Thread schreibt. Das nicht-generische Hashtable hat diese Eigenschaft, according to MSDN, aber leider ist es nicht in der PCL verfügbar ...

Gibt es eine andere Sammelklasse in der PCL, die diese Anforderung erfüllt? Wenn nicht, was wäre ein guter Weg, Gewindesicherheit zu erreichen, ohne für Lesevorgänge zu sperren? (Für Schreib Verriegelung ist in Ordnung, da es nicht zu oft passieren wird)


EDIT: Dank JaredPar Führung, ich implementiert schließlich meinen Cache in eine vollständig schleusenfreien Art und Weise, mit ImmutableDictionary<TKey, TValue> von 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

Haben Sie erwogen, einen Typ zu schreiben, der einen unveränderlichen Baum umhüllte, und ein CAS für schreibt? Das würde Ihnen die Lock-Free-Reads geben, CAS schreiben und Sie könnten Eric's unveränderlichen AVL-Tree als Backing-Struktur verwenden http://blogs.msdn.com/b/ericlippert/archive/2008/01/21/immutability-in- c-part-newer-akademisch-plus-my-avl-tree-implementation.aspx – JaredPar

+0

@ JaredPar, was ist "CAS"? –

+0

CAS = vergleichen und tauschen. – JaredPar

Antwort

4

Eine Option, die in Betracht gezogen werden sollte, ist, eine dünne Fassade über einen unveränderlichen Suchbaum zu schreiben. Es gibt mehrere unveränderliche Suchbäume, die im Internet zur Auswahl stehen. Ich stütze Mine in der Regel weg von Eric Lipperts großen Beitrag zum Thema

diese Verwendung als Strukturträger Daten werden Ihnen kostenlos sperren. Schreibzugriffe auf den Baum können auch in lockfreier Weise mit CAS durchgeführt werden. Dies wird etwas langsamer als ConcurrentDictionary sein, da Suchvorgänge O (Log (N)) sind, anstatt sich O (1) zu nähern. Aber es sollte den Trick für Sie tun

+0

Tolle Lösung, danke! Bezüglich der schreibfreien Schreibvorgänge weiß ich nicht, wie ich es erreichen soll ... Wenn ich nicht sperre und jeder Writer-Thread eine andere Kopie erstellt, wird die zweite überschrieben, was die erste getan hat, oder nicht? –

+0

Hier ist, wie ich den Baum jetzt verwende: https://gist.github.com/thomaslevesque/92ad1f8643dfa7a2970a –

+0

@ThomasLevesque werfen Sie einen Blick auf die Bearbeitungen, die ich gemacht habe. Ich habe versucht, die Logik in den Kommentaren zu erklären https://gist.github.com/jaredpar/20fbdb7ad7fbbb4bd82d – JaredPar

Verwandte Themen