ConcurrentDictionary替代可移植类库

时间:2013-08-21 21:15:23

标签: c# caching collections concurrency thread-safety

我正在编写一个面向.NET 4.5,Windows应用商店应用和Windows Phone 8的可移植类库。我需要一个高效的内存缓存机制,所以我考虑使用ConcurrentDictionary<K,V>,但它不是在WP8中可用。

会有很多读取和相对较少的写入,所以理想情况下我想要一个支持来自多个线程的无锁读取的集合,并由单个线程写入。非通用Hashtable具有该属性according to MSDN,但不幸的是,它在PCL中不可用...

PCL中是否有另一个符合此要求的集合类?如果没有,那么在不锁定读取的情况下实现线程安全的好方法是什么? (锁定写入是可以的,因为它不会经常发生)


编辑:感谢JaredPar的指导,我最终使用来自Microsoft.Bcl.ImmutableImmutableDictionary<TKey, TValue>以完全无锁的方式实现了我的缓存:

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();
    }
}

1 个答案:

答案 0 :(得分:4)

要考虑的一个选项是在不可变搜索树上编写精简外观。网上有几个不可变的搜索树可供选择。我通常根据Eric Lipperts关于这个主题的重要帖子奠定基础

使用它作为支持数据结构将使您无锁。写入树也可以使用CAS以无锁方式完成。这将比ConcurrentDictionary慢一点,因为查找是O(Log(N))而不是接近O(1)。但它应该为你做的伎俩