san*_*erd 5 .net c# memorycache
我正在使用(.NET 4.5)MemoryCache,与SlidingExpiration结合使用.
我注意到方法.AddOrGetExisting()似乎没有考虑到期,而.Get()确实如此.
单元测试:
[TestMethod]
public void NonWorking()
{
var memCache = new MemoryCache("somekey");
var cachePolicy = new CacheItemPolicy() { SlidingExpiration = TimeSpan.FromSeconds(1) };
var cacheEntry = memCache.AddOrGetExisting("key1", "foo", cachePolicy);
Assert.AreEqual(null, cacheEntry); // OK: AddOrGetExisting returns null, because it wasn't existing yet
Thread.Sleep(1100);
// Expecting null, since the existing item for key1 has expired by now.
// It is, however, still "foo".
Assert.AreEqual(null, memCache.AddOrGetExisting("key1", "bar", cachePolicy));
// FYI: afterwards, memCache.Get("key1") still equals "foo"
}
[TestMethod]
public void Working()
{
var memCache = new MemoryCache("somekey");
var cachePolicy = new CacheItemPolicy() { SlidingExpiration = TimeSpan.FromSeconds(1) };
var cacheEntry = memCache.AddOrGetExisting("key1", "foo", cachePolicy);
Assert.AreEqual(null, cacheEntry); // OK: AddOrGetExisting returns null, because it wasn't existing yet
Thread.Sleep(1100);
Assert.AreEqual(null, memCache.Get("key1"));
}
Run Code Online (Sandbox Code Playgroud)
题:
这是.AddOrGetExisting()的预期行为吗?
我可以回到.Get()然后,如果为null,.Add().
但是,因此我必须实现自己的锁定以确保线程安全.
问题出在AddOrGetExisting的第二次调用上。调用该方法时,它会创建 .net Framework 的 MemoryCacheEntry SourceCode的新实例。在此条目中,它将 Expiration 设置为 UtcNow + 1 Second,使您的 Thread.Sleep 毫无用处。(参见构造函数的这一行)
我不知道为什么它不使用现有条目的策略来确定超时。我猜这一行应该使用existingEntry 而不是entry。也许这是一个错误?
这是框架中产生“不当行为”的代码
existingEntry = _entries[key] as MemoryCacheEntry;
// has it expired?
if (existingEntry != null && /* THERE => */ entry.UtcAbsExp <= DateTime.UtcNow) {
toBeReleasedEntry = existingEntry;
toBeReleasedEntry.State = EntryState.RemovingFromCache;
existingEntry = null;
}
Run Code Online (Sandbox Code Playgroud)
existingEntry 是应该过期的“旧条目”,entry 是具有未过期 UtcAbsExp 值的新条目。