我有一个场景,我需要在第一次调用时暂时缓存来自webapi的信息。使用相同的参数,这个API可以每秒调用几次。
由于性能限制,我不希望每次调用获取数据并将其放入内存缓存中,因此我实现了一个带有Semaphores的系统,尝试允许一个线程初始化缓存,然后允许其余的只是查询缓存。
我已经删除了代码,以显示我目前正在做的事情。
private static MemoryCacher memCacher = new MemoryCacher();
private static ConcurrentDictionary<string, Semaphore> dictionary = new ConcurrentDictionary<string, Semaphore>();
private async Task<int[]> DoAThing(string requestHash)
{
// check for an existing cached result before hitting the dictionary
var cacheValue = memCacher.GetValue(requestHash);
if (cacheValue != null)
{
return ((CachedResult)cacheValue).CheeseBurgers;
}
Semaphore semi;
semi = dictionary.GetOrAdd(requestHash, new Semaphore(1, 1, requestHash));
semi.WaitOne();
//It's possible a previous thread has now filled up the cache. Have a squiz.
cacheValue = memCacher.GetValue(requestHash);
if (cacheValue != null)
{
dictionary.TryRemove(requestHash);
semi.Release();
return ((CachedResult)cacheValue).CheeseBurgers;
}
// fetch the latest data from the relevant web api
var response = await httpClient.PostAsync(url, content);
// add the result to the cache
memCacher.Add(requestHash, new CachedResult() { CheeseBurgers = response.returnArray }, DateTime.Now.AddSeconds(30));
// We have added everything to the cacher so we don't need this semaphore in the dictonary anymore:
dictionary.TryRemove(requestHash);
//Open the floodgates
semi.Release()
return response.returnArray;
}
不幸的是,有很多奇怪的问题,一次有多个线程设法通过WaitOne()调用,然后释放时由于信号量的计数限制而导致中断。 (确保一次只有一个信号量正在工作) 我已经尝试过使用Mutexes和Monitors,但是由于IIS不能保证API调用总是在同一个线程上运行,因此当尝试在另一个线程中释放互斥锁时,会导致它定期失败。
任何有关实施此方法的建议都会受到欢迎!