这是ConcurrentDictionary ThreadSafe吗?
private static ConcurrentDictionary<string, DateTime> dictionary= new ConcurrentDictionary<string, DateTime>();
public bool TextInputRecently(string text)
{
dictionary = new ConcurrentDictionary<string, DateTime>( dictionary.Where(pair => pair.Value.Ticks >= DateTime.Now.AddMinutes(-5).Ticks)
.ToDictionary(pair => pair.Key,
pair => pair.Value));
if (dictionary.ContainsKey(text))
return true;
dictionary.TryAdd(text, DateTime.Now);
return false;
}
我认为不是这样,因为可以在另一个线程检查键是否存在的同时重新创建字典。
我会更好地遍历字典,删除过时的值吗?
答案 0 :(得分:4)
否;字典可能会在ContainsKey()
和TryAdd()
之间改变。
除非您确定自己不在乎它们之间是否发生变化,否则切勿在{{1}}上连续调用两个方法。
同样,您也无法循环浏览字典,因为字典可能会在循环过程中发生变化。
相反,您应该使用其更复杂的方法(例如ConcurrentDictionary
,它将检查并添加单个原子操作。
另外,正如您所建议的,整个字典可能会被替换。
答案 1 :(得分:0)
感谢答案。
我遵循了Scott Hannen的建议,并用MemoryCache代替了它。如果有人要的话,以下是这些代码,请紧跟Locking pattern for proper use of .NET MemoryCache。
private static MemoryCache cache;
static readonly object cacheLock = new object();
private int expiry_timeout = 5;
public bool TextInputRecently(string text)
{
//Returns null if the string does not exist, prevents a race condition where the cache invalidates between the contains check and the retrieval.
var cachedString = MemoryCache.Default.Get(text, null) as string;
if (cachedString != null)
return true;
lock (cacheLock)
{
//Check to see if anyone wrote to the cache while we where waiting our turn to write the new value.
cachedString = MemoryCache.Default.Get(text, null) as string;
if (cachedString != null)
return true;
//The value still did not exist so we now write it in to the cache.
CacheItemPolicy cip = new CacheItemPolicy()
{
AbsoluteExpiration = new DateTimeOffset(DateTime.Now.AddSeconds(expiry_timeout))
};
MemoryCache.Default.Set(text, "", cip);
return false;
}
}
也许有更好的解决方案,但这可以满足我的需求。