繁体   English   中英

用于频繁读取和罕见写入操作的并发收集(.NET)

[英]Concurrent collection to use for frequent read and rare write operations (.NET)

我想在我的Web应用程序中创建一个缓存,这将允许顶层(MVC)持久保存从底层(服务和数据库)检索的某些值,以避免对它的不必要的请求。 我希望在网站的每个页面上存储我想要存储在缓存中的数据,因此该缓存旨在显着减少请求量。 这个想法是很多线程将从集合中读取数据,而一个线程将清除它并在缓存过期后检索新数据。 这意味着该集合将用于频繁阅读罕见的书写操作。

对我来说,问题是为这些目的选择合适的类。 我已经阅读了.NET 4中引入的System.Collections.Concurrent的并发类集。我绝对不需要使用ConcurrentQueueConcurrentStack ,但我必须在BlockingCollectionConcurrentBagConcurrentDictionary之间进行选择。

在这种情况下, ConcurrentBag似乎是最好的解决方案。 但是,我在这篇文章中读到了并发字典

...对于读取操作完全没有锁定。 通过这种方式,它针对从字典中读取最频繁操作的情况进行了优化。

那么最好的解决方案是使用ConcurrentDictionary<int, MyTypeOfObj>吗? 或者我可能根本不需要并发类型,简单的List会完成这项工作吗? 可能,如果我可以以某种方式锁定缓存更新时的操作,它会这样做。 但是使用简单的lock是不可取的。

任何建议和解释都表示赞赏。

更新

缓存用于存储插座的地图点。 这组插座非常稳定,但应该有一个UI来添加它们,因此插入操作非常少见。 在超时后从底层执行整个集合然后执行插入操作可能更容易。 也不需要搜索,阅读意味着简单的枚举。

根据对问题的评论,我决定使用MemoryCache (事实上​​,我并不是很清楚)。 由于我不需要为数据分离缓存实例,因此我使用保存在Default属性中的缓存:

除非需要,否则不要创建MemoryCache实例。 (...)如果在应用程序中只创建一个缓存实例,请使用默认缓存,并在需要访问缓存时从Default属性获取对它的引用。

链接(MSDN)

我通过以下方式初始化缓存:

private static MemoryCache _instance = MemoryCache.Default;

public static IEnumerable<MyDto> GetDtos()
{
    var result = _instance.Get(SOME_NAME);
    if (result == null)
        result = InitializeCache();
    return result;
}

没有用于阅读操作的锁。 然后,在InitializeCache锁定一个以防止多个请求:

private static IEnumerable<MyDto> InitializeCache()
{
    lock (_monitor) // here all threads but one will stop
    {
        var result = _instance.Get(SOME_NAME); // in case this thread is not the first who entered the lock
        if (result == null)
        {
            result = RetrieveSomeHowYourDataFromDbOrService();
            if (result == null)
                return null; // or exception
            _instance.Set(SOME_NAME, result, new CacheItemPolicy { AbsoluteExpiration = new DateTimeOffset(DateTime.Now.AddSeconds(TIMEOUT)), RemovedCallback = CacheClearedCallback}); 
        }
        return (IEnumerable<MyDto>)result;
    }
}

使用CacheItemPolicy允许清除过时的项目并从回调中再次检索项目:

private static void CacheClearedCallback(CacheEntryRemovedArguments arguments)
{
    InitializeCache();
}

在这种情况下,缓存将在没有来自消费者的请求的情况下进行更新(而不是在应用程序中的第一个请求中进行)。

可能,这不是有史以来最好的解决方案,但希望可以帮助某人,也许可以从一开始。 感谢您提示和评论。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM