2013-08-21 15 views
9

Piszę przenośną bibliotekę klas, która jest przeznaczona dla .NET 4.5, aplikacji Windows Store i Windows Phone 8. Potrzebuję wydajnego mechanizmu pamięci podręcznej w pamięci, więc pomyślałem o użyciu ConcurrentDictionary<K,V>, ale nie jest dostępny w WP8.Alternatywa dla ConcurrentDictionary dla przenośnej biblioteki klas

Będzie wiele odczytów i stosunkowo niewiele zapisów, więc najlepiej chciałbym kolekcji, która obsługuje bez blokady czytania z wielu wątków, i pisać przez jeden wątek. Nietypowy Hashtable ma tę właściwość, according to MSDN, ale niestety nie jest dostępny w PCL ...

Czy istnieje inna klasa kolekcji dostępna w PCL, która spełnia to wymaganie? Jeśli nie, jaki byłby dobry sposób na osiągnięcie bezpieczeństwa gwintu bez blokowania odczytu? (Blokowanie do zapisu jest OK, gdyż nie nastąpi zbyt często)


EDIT: dzięki kierunkiem JaredPar za, ja ostatecznie wdrożone pamięć podręczną w zupełnie lock-wolny sposób, stosując ImmutableDictionary<TKey, TValue> z 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

Czy rozważałeś napisanie typu, który zawinął niezmienne drzewo, i zrobił CAS do zapisu? To dałoby ci odczyty bez blokady, napisać CAS i możesz po prostu użyć niezmiennego drzewa AVL Erica jako struktury zaplecza http://blogs.msdn.com/b/ericlippert/archive/2008/01/21/immutability-in- c-part-nine-akademicki-plus-my-avl-tree-implementation.aspx – JaredPar

+0

@JaredPar, co to jest "CAS"? –

+0

CAS = porównaj i zamień. – JaredPar

Odpowiedz

4

Jedną z opcji do rozważenia jest napisanie cienkiej fasady nad niezmiennym drzewem wyszukiwania. Dostępnych jest wiele niezmiennych drzew wyszukiwania dostępnych w Internecie. I zazwyczaj oprzeć kopalni off Eric Lipperts wielki post na ten temat

Używając tego jako struktury danych podkład da zablokować darmo. Zapisywanie do drzewa może odbywać się w sposób wolny od zamków z CAS. To będzie nieco wolniej niż ConcurrentDictionary, ponieważ wyszukiwania są O (Log (N)) zamiast zbliżać się do O (1). Ale powinno ci się to udać

+0

Świetne rozwiązanie, dzięki! Jeśli chodzi o pisanie bez blokady, nie jestem pewien, jak to osiągnąć ... jeśli nie zablokuję, a każdy wątek będzie tworzył inną kopię, drugi nadpisze to, co zrobił pierwszy, prawda? –

+0

Oto jak teraz używam drzewa: https://gist.github.com/thomaslevesque/92ad1f8643dfa7a2970a –

+0

@ThomasLevesque zapoznaj się z wprowadzonymi przeze mnie zmianami. Próbowałem wyjaśnić logikę w komentarzach https://gist.github.com/jaredpar/20fbdb7ad7fbbb4bd82d – JaredPar

Powiązane problemy