public class SimpleMemoryCache{private MemoryCache _cache = new MemoryCache(new MemoryCacheOptions());
public TItem GetOrCreate(object key, Func createItem){TItem cacheEntry;
if (!_cache.TryGetValue(key, out cacheEntry))// Look for cache key.{// Key not in cache, so get data.cacheEntry = createItem();
// Save data in cache._cache.Set(key, cacheEntry);
}return cacheEntry;
}}
用法:
var _avatarCache = new SimpleMemoryCache();
// ...var myAvatar = _avatarCache.GetOrCreate(userId, () => _database.GetAvatar(userId));
public class MemoryCacheWithPolicy{private MemoryCache _cache = new MemoryCache(new MemoryCacheOptions(){SizeLimit = 1024});
public TItem GetOrCreate(object key, Func createItem){TItem cacheEntry;
if (!_cache.TryGetValue(key, out cacheEntry))// Look for cache key.{// Key not in cache, so get data.cacheEntry = createItem();
var cacheEntryOptions = new MemoryCacheEntryOptions().SetSize(1)//Size amount//Priority on removing when reaching size limit (memory pressure).SetPriority(CacheItemPriority.High)// Keep in cache for this time, reset time if accessed..SetSlidingExpiration(TimeSpan.FromSeconds(2))// Remove from cache after this time, regardless of sliding expiration.SetAbsoluteExpiration(TimeSpan.FromSeconds(10));
// Save data in cache._cache.Set(key, cacheEntry, cacheEntryOptions);
}return cacheEntry;
}}
public class WaitToFinishMemoryCache{private MemoryCache _cache = new MemoryCache(new MemoryCacheOptions());
private ConcurrentDictionary _locks = new ConcurrentDictionary();
public async Task GetOrCreate(object key, Func> createItem){TItem cacheEntry;
if (!_cache.TryGetValue(key, out cacheEntry))// Look for cache key.{SemaphoreSlim mylock = _locks.GetOrAdd(key, k => new SemaphoreSlim(1, 1));
await mylock.WaitAsync();
try{if (!_cache.TryGetValue(key, out cacheEntry)){// Key not in cache, so get data.cacheEntry = await createItem();
_cache.Set(key, cacheEntry);
}}finally{mylock.Release();
}}return cacheEntry;
}}
用法:
var _avatarCache = new WaitToFinishMemoryCache();
// ...var myAvatar = await _avatarCache.GetOrCreate(userId, async () => await _database.GetAvatar(userId));
4、代码说明
此实现锁定项目的创建。锁是特定于钥匙的。例如,如果我们正在等待获取 Alex 的 Avatar,我们仍然可以在另一个线程上获取 John 或 Sarah 的缓存值。
字典 _locks 存储了所有的锁。常规锁不适用于 async/await ,因此我们需要使用 SemaphoreSlim [5] . 【C#|C# .NET 中的缓存实现详情】如果 (!_cache.TryGetValue(key, out cacheEntry)),有 2 次检查以查看该值是否已被缓存。锁内的那个是确保只有一个创建的那个。锁外面的那个是为了优化。