Async threadsafe Get from MemoryCache

后端 未结 4 1158
北海茫月
北海茫月 2020-12-01 03:13

I have created a async cache that uses .NET MemoryCache underneath. This is the code:

public async Task GetAsync(string key, Func

        
4条回答
  •  清歌不尽
    2020-12-01 03:51

    Although there is an already accepted answer, I'll post a new one with Lazy approach. Idea is: to minimize the duration of lock block, if the key doesn't exists in cache, put a Lazy to cache. That way all threads using the same key at the same time will be waiting the same Lazy's value

    public Task GetAsync(string key, Func> populator, TimeSpan expire, object parameters)
    {
        if (parameters != null)
            key += JsonConvert.SerializeObject(parameters);
    
        lock (_cache)
        {
            if (!_cache.Contains(key))
            {
                var lazy = new Lazy>(populator, true);
                _cache.Add(key, lazy, DateTimeOffset.Now.Add(expire));
            }
        }
    
        return ((Lazy>)_cache.Get(key)).Value;
    }
    

    Version2

    public Task GetAsync(string key, Func> populator, TimeSpan expire, object parameters)
    {
        if (parameters != null)
            key += JsonConvert.SerializeObject(parameters);
    
        var lazy = ((Lazy>)_cache.Get(key));
        if (lazy != null) return lazy.Value;
    
        lock (_cache)
        {
            if (!_cache.Contains(key))
            {
                lazy = new Lazy>(populator, true);
                _cache.Add(key, lazy, DateTimeOffset.Now.Add(expire));
                return lazy.Value;
            }
            return ((Lazy>)_cache.Get(key)).Value;
        }
    }
    

    Version3

    public Task GetAsync(string key, Func> populator, TimeSpan expire, object parameters)
    {
        if (parameters != null)
            key += JsonConvert.SerializeObject(parameters);
    
        var task = (Task)_cache.Get(key);
        if (task != null) return task;
    
        var value = populator();
        return 
         (Task)_cache.AddOrGetExisting(key, value, DateTimeOffset.Now.Add(expire)) ?? value;
    }
    

提交回复
热议问题