深入理解.NET MemoryCache (4)

其他的场景都比较好理解,其中值得一提的就是场景1(遍历)的实现方式。在MemoryCache中,使用了锁加复制的方式来处理遍历的需要,保证在遍历过程中不会发生异常。

在.net 4.5.1中的遍历的实现方式是这样的:

protected override IEnumerator<KeyValuePair<string, object>> GetEnumerator() { Dictionary<string, object> h = new Dictionary<string, object>(); if (!IsDisposed) { foreach (MemoryCacheStore store in _stores) { store.CopyTo(h); } } return h.GetEnumerator(); }

其中store.CopyTo(h);的实现方式是在MemoryCacheStore中定义的,也就是说,每个Store的加锁解锁都是独立的过程,缩小锁机制影响的范围也是提升性能的重要手段。CopyTo方法的主要逻辑是在锁机制控制下的简单的遍历:

internal void CopyTo(IDictionary h) { lock (_entriesLock) { if (_disposed == 0) { foreach (DictionaryEntry e in _entries) { MemoryCacheKey key = e.Key as MemoryCacheKey; MemoryCacheEntry entry = e.Value as MemoryCacheEntry; if (entry.UtcAbsExp > DateTime.UtcNow) { h[key.Key] = entry.Value; } } } } }

有些出乎意料,在遍历MemoryCache的时候,为了实现遍历过程中的线程安全,实现的方式居然是将数据另外拷贝了一份。当然了,说是完全拷贝一份也不尽然,如果缓存项本来就是引用类型,被拷贝的也只是个指针而已。不过看起来最好还是少用为妙,万一缓存的都是些基础类型,一旦数据量较大,在遍历过程中的内存压力就不是可以忽略的问题了。

总结

在本文中以MemoryCache对于数据的组织管理和使用为轴线,深入的分析了MemoryCache对于一些日常应用有直接关联的功能的实现方式。MemoryCache通过多个MemoryCacheStore对象将数据分散到不同的HastTable中,并且使用加锁的方式在每个Store内部保证操作是线程安全的,同时这种逻辑也在一定程度上改善了全局锁的性能问题。为了实现对于缓存项超时的管理,MemoryCache采取了两种不同的管理措施,双管齐下,有效保证了缓存项的超时管理的有效性,并在超时后及时移除相关的缓存以释放内存资源。通过对于这些功能的分析,了解了MemoryCache内部的数据结构和数据查询方式,为今后的工作掌握了许多有指导性意义的经验。

参考资料

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpfpgd.html