1

我一直想知道何时何地是缓存属性值的最佳时间......其中一些看起来很简单,就像下面的那个......

public DateTime FirstRequest {
    get {
        if (this.m_FirstRequest == null) {
            this.m_FirstRequest = DateTime.Now;
        }
        return (DateTime)this.m_FirstRequest;
    }
}
private DateTime? m_FirstRequest;

但是一些更复杂的情况呢?

  1. 来自数据库的值,但在被选中后仍然为真。
  2. 存储在内置缓存中并且可能不时过期的值。
  3. 必须首先计算的值?
  4. 需要一些时间来初始化的值。0.001 秒、0.1 秒、1 秒、5 秒???
  5. 已设置的值,但可能会出现其他内容并将其设置为 null 以标记应重新填充它。
  6. ???似乎有无限的情况。

你认为一个属性不能再照顾自己而是需要一些东西来填充它的价值是什么?


[编辑]

我看到一些建议说我优化得太早了,等等。但我的问题是什么时候优化。缓存所有内容不是我要的,但是当需要缓存时,应该由谁负责?

4

2 回答 2

2

一般来说,您应该先让代码工作,然后再进行优化,然后只进行分析认为对您有帮助的优化。

于 2008-12-04T18:40:31.787 回答
1

我认为你需要把你的问题反过来,以免你陷入过早优化的陷阱。

您认为何时不再需要在每次调用时重新计算属性而是使用某种形式的缓存?

值的缓存是一种优化,因此不应作为规范进行。在某些情况下,使用此优化显然是相关的,但在大多数情况下,您应该通过执行适当的工作来获取值,然后在分析和显示后寻求优化它,从而使该属性每次都能正常工作需要优化。

缓存是或不是一个好主意的一些原因: - 如果值容易频繁更改,请不要缓存 - 如果它永远不会更改并且您负责它永远不会更改,请不要缓存 - 如果您不负责,请不要缓存提供价值,因为您依赖于其他人的实施

支持和反对缓存值的原因还有很多,但对于何时缓存和何时不缓存当然没有硬性规定——每种情况都不同。

如果你必须缓存...

假设您已经确定某种形式的缓存是可行的方法,那么执行缓存的方式取决于您要缓存的内容、原因以及向您提供值的方式。

例如,如果它是一个单例对象或您的示例中的时间戳,一个简单的“它设置了吗?” 设置一次值的条件是一种有效的方法(或者在构造期间创建实例)。但是,如果它正在访问数据库并且数据库告诉您它何时更改,您可以基于一个脏标志缓存该值,只要数据库值表明它已更改,该标志就会变脏。当然,如果您没有更改通知,那么您可能必须在每次调用时刷新值,或者在检索之间引入最短等待时间(当然,接受值可能并不总是准确的)。

无论哪种情况,您都应该始终考虑每种方法的优缺点,并考虑引用该值的场景。消费者是否总是需要最新的价值,或者他们可以应对稍微落后的情况?你能控制价值的来源吗?来源是否提供更改通知(或者您可以使其提供此类通知)?来源的可靠性如何?有许多因素会影响您的方法。

考虑到你给出的场景......

同样,假设需要缓存。

  1. 来自数据库的值,但在被选中后仍然为真。
    如果保证数据库保留该行为,您可以在第一次请求该值时轮询该值,然后将其缓存。如果您不能保证数据库的行为,您可能需要更加小心。

  2. 存储在内置缓存中并且可能不时过期的值。
    我会使用脏标志方法,其中缓存不时被标记为脏,以指示缓存的值需要刷新,假设您知道“不时”是什么时候。如果不这样做,请考虑使用一个计时器来定期指示缓存是脏的。

  3. 必须首先计算的值?
    我会根据价值来判断这一点。即使您认为需要缓存,编译器也可能已经对其进行了优化。但是,假设需要缓存,如果计算时间很长,那么在构建期间或通过诸如ISupportInitialize.

  4. 需要一些时间来初始化的值。0.001s、0.1s、1s、5s???
    我会让属性对此不进行计算并实现一个指示值何时发生变化的事件(这在值可能发生变化的任何情况下都是一种有用的方法)。一旦初始化完成,事件就会触发,允许消费者获取值。您还应该考虑到这可能不适合房产;相反,请考虑一种异步方法,例如带有回调的方法。

  5. 已设置的值,但可能会出现其他内容并将其设置为 null 以标记应重新填充它。
    这只是第 2 点中讨论的脏标志方法的一个特例。

于 2008-12-04T18:38:13.040 回答