【发布时间】:2018-11-21 15:55:19
【问题描述】:
我正在尝试为 API 创建自己的缓存实现。这是我第一次使用 ConcurrentDictionary,我不知道我是否正确使用它。在测试中,出现了一些错误,到目前为止我还无法再次重现它。也许一些并发专业人士/ConcurrentDictionary 可以查看代码并找出可能出错的地方。谢谢!
private static readonly ConcurrentDictionary<string, ThrottleInfo> CacheList = new ConcurrentDictionary<string, ThrottleInfo>();
public override void OnActionExecuting(HttpActionContext actionExecutingContext)
{
if (CacheList.TryGetValue(userIdentifier, out var throttleInfo))
{
if (DateTime.Now >= throttleInfo.ExpiresOn)
{
if (CacheList.TryRemove(userIdentifier, out _))
{
//TODO:
}
}
else
{
if (throttleInfo.RequestCount >= defaultMaxRequest)
{
actionExecutingContext.Response = ResponseMessageExtension.TooManyRequestHttpResponseMessage();
}
else
{
throttleInfo.Increment();
}
}
}
else
{
if (CacheList.TryAdd(userIdentifier, new ThrottleInfo(Seconds)))
{
//TODO:
}
}
}
public class ThrottleInfo
{
private int _requestCount;
public int RequestCount => _requestCount;
public ThrottleInfo(int addSeconds)
{
Interlocked.Increment(ref _requestCount);
ExpiresOn = ExpiresOn.AddSeconds(addSeconds);
}
public void Increment()
{
// this is about as thread safe as you can get.
// From MSDN: Increments a specified variable and stores the result, as an atomic operation.
Interlocked.Increment(ref _requestCount);
// you can return the result of Increment if you want the new value,
//but DO NOT set the counter to the result :[i.e. counter = Interlocked.Increment(ref counter);] This will break the atomicity.
}
public DateTime ExpiresOn { get; } = DateTime.Now;
}
【问题讨论】:
-
你遇到了什么错误?
-
这就是问题所在,当它发生时,我没有做笔记,现在我无法重现它。我试过了,但我做不到。我认为这是一个并发问题。在某些时候,2 个或更多线程想要对同一个对象做某事并破坏代码。几行代码,也许是一些专家,可以可视化并发现一些错误。这是我第一次使用 ConcurrentDictionary
-
ConcurrentDictionary类只适用于非常琐碎的缓存场景。对于更高级的东西(如过期策略),有专门的类可用。像System.Runtime.Caching.MemoryCache(带有string键)和较新的Microsoft.Extensions.Caching.Memory.MemoryCache(带有object键)。后者提供更多优先级选项。我强烈建议使用其中之一。
标签: c# multithreading thread-safety concurrentdictionary