5

(.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"));
    }

質問:

これは.AddOrGetExisting()の予想される動作ですか?

.Get() にフォールバックし、null の場合は .Add() にフォールバックできます。
ただし、その結果、スレッドセーフを確保するために独自のロックを実装する必要があります。

4

2 に答える 2

3

問題は、AddOrGetExisting の 2 番目の呼び出しにあります。メソッドを呼び出すと、 .net Frameworkの MemoryCacheEntry SourceCode の新しいインスタンスが作成されます 。このエントリでは、有効期限を UtcNow + 1 秒に設定し、Thread.Sleep を役に立たなくします。(コンストラクターのこの行を参照)

ただし、既存のエントリのポリシーを使用してタイムアウトを決定しない理由はわかりません。このは、私が推測するエントリの代わりに existingEntry を使用する必要があります。多分これはバグですか?

「誤動作」を生成するフレームワークのコードは次のとおりです。

existingEntry = _entries[key] as MemoryCacheEntry;
// has it expired?
if (existingEntry != null && /* THERE => */ entry.UtcAbsExp <= DateTime.UtcNow) {
    toBeReleasedEntry = existingEntry;
    toBeReleasedEntry.State = EntryState.RemovingFromCache;
    existingEntry = null;
}

existingEntry は有効期限が切れる「古いエントリ」で、有効期限が切れていない UtcAbsExp 値を持つ新しいエントリです。

于 2014-08-04T13:31:57.560 に答える