我想在我的Web应用程序中创建一个缓存,这将允许顶层(MVC)持久保存从底层(服务和数据库)检索的一些值,以避免对它的不必要的请求。我希望在网站的每个页面上存储我想要存储在缓存中的数据,因此该缓存旨在显着减少请求量。这个想法是很多线程将从集合中读取数据,而一个线程将清除它并在缓存过期后检索新数据。这意味着该集合将用于频繁阅读和罕见写作操作。
对我来说,问题是为这些目的选择合适的类。我已经阅读了.NET 4中引入的System.Collections.Concurrent
并发类的集合。我绝对不需要使用ConcurrentQueue
或ConcurrentStack
,但我必须在{{{{}}之间进行选择。 3}},BlockingCollection
和ConcurrentBag
。
ConcurrentBag
似乎是最好的解决方案。但是,我在ConcurrentDictionary
中读到并发字典
...对于读取操作完全无锁。通过这种方式,它针对从字典中读取最频繁操作的场景进行了优化。
所以也许最好的解决方案是使用ConcurrentDictionary<int, MyTypeOfObj>
代替?或者我可能根本不需要并发类型,简单的List
会完成这项工作吗?可能,如果我可以以某种方式锁定缓存更新时的操作,它会这样做。但是使用简单的lock
是不可取的。
感谢任何建议和解释。
缓存用于存储插座的地图点。这组插座非常稳定,但应该有一个UI来添加它们,因此插入操作非常少见。在超时后从底层执行整个集合然后执行插入操作可能更容易。也不需要搜索,阅读意味着简单的枚举。
答案 0 :(得分:0)
根据对问题的评论,我决定使用MemoryCache
(事实上,我并不十分清楚)。由于我不需要为数据分隔缓存实例,因此我使用保存在Default
属性中的缓存:
除非需要,否则不要创建MemoryCache实例。 (...)如果在应用程序中只创建一个缓存实例,请使用默认缓存,并在需要访问缓存时从Default属性获取对它的引用。
按以下方式初始化缓存I:
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();
}
在这种情况下,缓存将在没有来自消费者的请求的情况下进行更新(而不是在应用程序的第一个请求中进行)。
可能这不是有史以来最好的解决方案,但希望对某人有帮助,也许可以从一开始。感谢您的提示和意见。