我正在尝试优化用作数据库查询缓存的字典的每个字符串键的字符串比较操作的性能。目前的代码如下:
public void Clear(string tableName)
{
foreach (string key in cache.Keys.Where(key => key.IndexOf(tableName, StringComparison.Ordinal) >= 0).ToList())
{
cache.Remove(key);
}
}
我是使用C#并行功能的新手,我想知道将其转换为并行操作的最佳方法是什么,这样多个字符串比较可以“同时”发生。缓存通常会变得非常大,因此使用Clear()
进行维护可能会非常昂贵。
答案 0 :(得分:1)
将cache
对象设为ConcurrentDictionary并使用TryRemove
代替Remove
。
这将使您的缓存线程安全;然后,可以像这样调用当前的foreach
循环:
Parallel.ForEach(cache.Keys, key =>
{
if(key.IndexOf(tableName, StringComparison.Ordinal) >= 0)
{
dynamic value; // just because I don't know your dictionary.
cache.TryRemove(key, out value);
}
});
希望能给你一个起点。
答案 1 :(得分:1)
您的方法在Dictionary<string, Whatever>
上无法正常工作,因为该类对多个编写者来说不是线程安全的,因此同时删除可能会导致各种问题。
因此,您必须使用锁来同步删除,这将使字典的访问基本上是单线程的。关于可以在线程中同时安全完成的唯一事情是Where
中的比较。
您可以使用ConcurrentDictionary
,因为它使用条带锁可以减少这种影响。它似乎仍然不是最好的方法。
如果要从字符串构建密钥以便测试密钥是否以子密钥开头,并且经常需要删除整个子密钥,则可以尝试使用Dictionary<string, Dictionary<string, Whatever>>
。添加或更新变得有点贵,但清除成为从高级字典中删除一个值的O(1)。
答案 2 :(得分:0)
我之前使用过Dictionaries作为缓存,而我以前做的就是“动态”清理缓存,也就是说,每个条目我也包含它的包含时间,然后随时要求输入我删除旧条目。性能损失对我来说很小,但如果需要,您可以实现一个队列(Tuple<DateTime, TKey>
,其中TKey
是您字典上的键的类型)作为保存这些时间戳的索引,这样您就不需要了每次迭代整个字典。无论如何,如果你不得不考虑这些问题,是时候考虑使用专用的缓存服务器了。对我来说,共享缓存(http://sharedcache.codeplex.com)已经足够好了。