我有一个会话的概念,它存储各种状态的对象。
有时我需要扫描会话以查找与特定查询匹配的对象,但是我做了很多,性能测试表明它已成为某些领域的瓶颈。
因此,我想在Session上介绍索引的概念。
像...一样的东西。
public IDictionary<K, V> GetIndex<K, V>(Func<V, K> keySelector)
但是我不确定如何像这样测试Func的“相等”。显然我希望索引只能在第一次调用GetIndex和后续调用时再构建它。
我应该如何在内部映射以进行索引存在查找?
IDictionary<???, IDictionary<K, V>> indexes = ...
基本上我应该如何存储???。也许我不能用Func做到这一点,但也许还有其他方法。
答案 0 :(得分:1)
最简单的方法可能是计算查询的哈希值,并使用哈希作为键将结果插入到字典中。
如果您的查询是字符串,您可以使用string.GetHashCode函数来计算字符串数据的简单哈希。如果您的查询是Linq查询,.GetHashCode可能无法工作,除非Linq专门覆盖此方法以计算表达式树而不是默认对象实例指针的哈希值。 .GetHashCode的默认实现只返回一个从内存中的对象实例标识派生的值,而不考虑对象的数据内容。
如果您的查询是字符串并且在构造上相当一致/一致,那么计算简单的字符串哈希应该足以使用缓存减少查询流量。如果您的查询在结构上不太一致(例如,等效查询但是参数的顺序不同),您可能需要构建自己的哈希函数,该哈希函数在输入查询的规范化形式上计算哈希,以提高查询的缓存命中率在逻辑上等同但在文本上不同。
随着哈希计算的计算成本越来越高,它将降低使用缓存的性能提升。确保查询操作足够昂贵,以证明花费时间计算哈希值并为缓存消耗内存以节省执行时间。查询操作应该比散列计算和缓存管理开销大至少2个或更多个数量级。如果您的查询操作是进程外或跨网络调用,那么您的缓存开销几乎肯定会因查询成本而相形见绌。
答案 1 :(得分:1)
您可以考虑在需要执行时使用Expression<Func<K,V>>
然后使用Compile()
表达式。
为了检查平等,请看一下这个问题:
How to check if two Expression<Func<T, bool>> are the same
或者,您可以为索引指定名称并继续使用委托:
public IDictionary<K, V> GetIndex<K, V>(string indexName, Func<V, K> keySelector)
IDictionary<string, IDictionary<K, V>> indexes = ..
答案 2 :(得分:1)
比较循环中的表达式可能比选择字典更耗时。 正如线程中已经指出的那样,有一些方法可以比较它们,但非常耗时且不准确:
x => x.Key == 1
VS
y => y.Key == 1
VS
int value = 1
x => x.Key == value
会给出错误的
因此,创建ad hoc索引不是一个好的解决方案。
你可以做的是拥有一个带有预定义表达式模板的Indexing工厂类,它们在第一次调用某些参数组合时创建表达式,并通过引用将它们(实例)与.Equals一起使用。
像(pseudoC#ode):
static class Indexfactory {
private static Dictionary<IndexcreationParams,Expression> ...
// more of these as required
public static Expression getIndex<Tret,P1,P2,P3,...>(IndexType type, P1 p1,P2 p2,P3 p3...) {
// create expression from template with the supplied parameters
// if not already existent, else rerturn it from static storage
// store expression in some private storage
}
}
然后将表达式作为键存储在字典中,并在首先执行时显示结果列表。在下面的执行中检查您是否已缓存此表达式的结果,因为如果您使用工厂,您将始终获得相同的引用。