【问题标题】:In-memory indexes内存索引
【发布时间】:2011-08-29 00:57:45
【问题描述】:

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

有时我需要扫描 Session 以查找与特定查询匹配的对象,但我经常这样做,性能测试表明它正在成为某些领域的瓶颈。

因此我想介绍一下 Session 上索引的概念。

类似...

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

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

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

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

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

【问题讨论】:

标签: c# .net dictionary indexing


【解决方案1】:

在循环中比较表达式可能比在字典中选择更耗时。 正如线程中已经指出的,有一些方法可以比较它们,但非常耗时且不准确:

x => x.Key == 1

y => y.Key == 1

int value = 1
x => x.Key == value

会报假

因此,临时创建索引并不是一个好的解决方案。

您可以做的是拥有一个带有预定义表达式模板的索引工厂类,该模板在第一次调用某些参数组合时创建表达式,并通过引用将它们(实例)与 .Equals 一起使用。

类似(伪C#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
   }
}

然后将表达式作为键存储在字典中,并在它首先执行时包含结果列表。在接下来的执行中检查你是否已经缓存了这个表达式的结果,因为如果你使用工厂,你总是会得到相同的引用。

【讨论】:

    【解决方案2】:

    您可以考虑在需要执行时使用Expression&lt;Func&lt;K,V&gt;&gt;Compile() 表达式。

    要检查相等性,请查看这个 SO 问题:
    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 = ..
    

    【讨论】:

      【解决方案3】:

      最简单的方法可能是计算查询的哈希,然后使用哈希作为键将结果插入到字典中。

      如果您的查询是字符串,您可以只使用 string.GetHashCode 函数来计算字符串数据的简单哈希。如果您的查询是 Linq 查询,则 .GetHashCode 可能不起作用,除非 Linq 专门重写此方法以计算表达式树上的哈希而不是默认对象实例指针。 .GetHashCode 的默认实现只返回一个从内存中的对象实例标识派生的值,而不考虑对象的数据内容。

      如果您的查询是字符串并且在构造上相当统一/一致,则计算简单的字符串哈希应该足以减少使用缓存的查询流量。如果您的查询在结构上不太一致(例如,等效查询但参数顺序不同),您可能需要构建自己的哈希函数来计算输入查询的规范化形式的哈希,以提高查询的缓存命中率逻辑上等价但文本不同。

      随着哈希计算的计算成本越来越高,它会降低使用缓存的性能增益。确保查询操作足够昂贵,以证明花费时间计算散列和消耗内存用于缓存以产生执行时间的净节省是合理的。查询操作应至少比哈希计算和缓存管理开销大 2 个或更多数量级。如果您的查询操作是进程外调用或跨网络调用,那么您的缓存开销几乎肯定会与查询成本相比相形见绌。

      【讨论】:

      • GetHashCode 返回的值不是唯一的。所以你不能将它们用作字典中的键。
      • 标准的 .net 字典已经实现了一个哈希表。使用哈希索引不会加快速度。
      • 好吧,GUIDS、SHA 和 CRC,...(列出一个列表)都不是唯一的,但它们仍然使用它们来实现唯一性。这里更大的问题是哈希码是每个实例的,所以任何查询都是新的。
      • 调试器可以将函数显示为字符串。此功能可能会有所帮助。
      • 不幸的是,对于某些表达式,您没有得到良好的字符串表示形式:/ 如果 MS 选择更改 ToString() 的工作方式,您不能保证您的代码将适用于所有框架或未来的框架他们。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-09-09
      • 2021-10-30
      • 2011-09-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多