内存索引

时间:2011-05-19 16:26:45

标签: c# .net dictionary indexing

我有一个会话的概念,它存储各种状态的对象。

有时我需要扫描会话以查找与特定查询匹配的对象,但是我做了很多,性能测试表明它已成为某些领域的瓶颈。

因此,我想在Session上介绍索引的概念。

像...一样的东西。

public IDictionary<K, V> GetIndex<K, V>(Func<V, K> keySelector)

但是我不确定如何像这样测试Func的“相等”。显然我希望索引只能在第一次调用GetIndex和后续调用时再构建它。

我应该如何在内部映射以进行索引存在查找?

IDictionary<???, IDictionary<K, V>> indexes = ...

基本上我应该如何存储???。也许我不能用Func做到这一点,但也许还有其他方法。

3 个答案:

答案 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
   }
}

然后将表达式作为键存储在字典中,并在首先执行时显示结果列表。在下面的执行中检查您是否已缓存此表达式的结果,因为如果您使用工厂,您将始终获得相同的引用。