Caching asynchronous operations

后端 未结 6 512
暖寄归人
暖寄归人 2020-12-28 16:40

I am looking for an elegant way of caching the results of my asynchronous operations.

I first had a synchronous method like this:

public String GetSt         


        
6条回答
  •  没有蜡笔的小新
    2020-12-28 17:26

    Here's a way to cache results of asynchronous operations that guarantees no cache misses.

    In the accepted answer, if the same url is requested many times in a loop (depending on the SynchronizationContext) or from multiple threads the web request will keep getting sent out until there's a response that gets cached, at which point the cache will start getting used.

    The method below creates a SemaphoreSlim object for each unique key. This will prevent the long running async operation from running multiple times for the same key while allowing it to be running simultaneously for different keys. Obviously, there's overhead keeping SemaphoreSlim objects around to prevent cache misses so it may not be worth it depending on the use case. But if guaranteeing no cache misses is important than this accomplishes that.

    private readonly ConcurrentDictionary _keyLocks = new ConcurrentDictionary();
    private readonly ConcurrentDictionary _cache = new ConcurrentDictionary();
    
    public async Task GetSomethingAsync(string key)
    {   
        string value;
        // get the semaphore specific to this key
        var keyLock = _keyLocks.GetOrAdd(key, x => new SemaphoreSlim(1));
        await keyLock.WaitAsync();
        try
        {
            // try to get value from cache
            if (!_cache.TryGetValue(key, out value))
            {
                // if value isn't cached, get it the long way asynchronously
                value = await GetSomethingTheLongWayAsync();
    
                // cache value
                _cache.TryAdd(key, value);
            }
        }
        finally
        {
            keyLock.Release();
        }
        return value;
    }
    

    Edit: As @mtkachenko mentioned in the comments, an additional cache check could be performed at the beginning of this method to potentially skip the lock acquisition step.

提交回复
热议问题