我有一个帮助器类,它读取一个大的XML文档并生成一个c#对象列表。
我使用这些对象非常多,所以我认为最好的方法是将它们保存在内存中,然后从那里访问它们。
我创建了一个简单的存储库,它从内存中获取一个对象,如果不存在,则添加它。
存储库看起来像这样:
public class XmlDocumentRepository
{
private readonly ICacheStorage _cacheStorage;
public XmlDocumentRepository(ICacheStorage cacheStorage)
{
_cacheStorage = cacheStorage;
}
private readonly object _locker = new object();
private void DeserializeXmlDocument()
{
lock (_locker)
{
// I deserialize the xml document, i generate the c# classes, and save them in cache
IEnumerable<Page> pages = new XmlDeserializerHelper().DeserializeXml();
foreach(var page in pages)
{
_cacheStorage.Add(page_Id, page);
}
}
}
public Page GetPage(Guid page_Id)
{
Page page = _cacheStorage.Get<Page>(page_Id);
if (page != null)
return page;
lock (_locker)
{
page = _cacheStorage.Get<Page>(page_Id);
if (page != null)
return page;
DeserializeXmlDocument();
page = _cacheStorage.Get<Page>(page_Id);
return page;
}
}
}
XmlDocumentRepository
在Web应用程序中使用(更真实的是asp.net mvc)。
存储库的实现是否良好?我正在使用lock
语句吗?
答案 0 :(得分:1)
在我对这个问题的评论中,我误解了共享的缓存。我认为您需要执行以下选项之一:
XmlDocumentRepository
成为在所有请求中使用的单例,因为锁对象是私有字段,因此每个请求都会有一个带有新字段的存储库的新实例。XmlDocumentRepository
实例之间共享。答案 1 :(得分:0)
作为主要规则,您希望保护多个线程使用的数据存储的所有访问变体。我看到你的实施有几个潜在的问题;
1:IChacheStorage是从外部提供的,这意味着可以在其他地方修改此集合,这可能会或可能不会受到锁的保护。也许您应该要求集合本身在内部使用锁定,或者其他类型的线程安全机制?
2:您对数据访问的锁定保护不一致。在GetPage中,您在应用锁之前访问_cacheStorage,而在反序列化中,您可以在锁内访问它。这意味着您可能会得到一个结果,其中一个正在添加到缓存而另一个正在从缓存中获取。
3:您是否需要缓存,xml读取或两者的线程安全性? 如果您只需要保护缓存,请在锁外移动读取xml。如果同时保护两者,则应将整个GetPage函数放在锁中。