你应该为一个属性缓存一个值?

时间:2008-12-04 17:50:45

标签: caching properties

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

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

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

  1. 来自数据库的值,但在选中后仍为true。
  2. 存储在内置缓存中的值,可能会不时到期。
  3. 必须先计算的值?
  4. 需要一些时间进行初始化的值。 0.001s,0.1s,1s, 5s ???
  5. 设置的值,但可能会出现其他内容并将其设置为null以标记应重新填充。
  6. ??? 似乎有无限的情况。
  7. 您认为某个地产无法再照顾自己而需要某些东西来填充其价值这一点是什么意思?


    [编辑]

    我看到的建议是我过早地进行了优化等等。但我的问题是什么时候进行优化。缓存一切并不是我所要求的,但是当它需要缓存时,它的责任应该是什么?

2 个答案:

答案 0 :(得分:2)

一般情况下,您应首先使代码工作,然后再进行优化,然后只进行分析所说的优化,这将对您有所帮助。

答案 1 :(得分:1)

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

您认为财产何时不再需要在每次通话时重新计算,而是使用某种形式的缓存?

值的缓存是一种优化,因此不应该作为标准来完成。在某些情况下,使用此优化显然是相关的,但在大多数情况下,您应该通过执行适当的工作来获取值,然后在配置和显示后优化它,以实现属性每次都正常工作需要进行优化。

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

还有许多其他原因支持和反对缓存值,但是当然没有关于何时缓存以及何时不缓存的硬性和快速规则 - 每种情况都不同。

如果你必须缓存......

假设您已确定某种形式的缓存是可行的方式,那么您执行缓存的方式取决于您缓存的内容,原因以及如何为您提供该值。

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

无论情况如何,您都应该始终考虑每种方法的优缺点,并考虑引用该值的方案。消费者是否总是需要最近的价值,还是他们可以应对略微落后的问题?您是否掌控了价值的来源?来源是否提供变更通知(或者您是否可以提供此类通知)?源的可靠性是什么?有许多因素会影响您的方法。

考虑你给出的情景......

再次,假设需要缓存。

  1. 来自数据库的值,但在选中后仍为true 如果保证数据库保留该行为,则可以在第一次请求时轮询该值并在此后对其进行缓存。如果您无法保证数据库的行为,您可能需要更加小心。

  2. 存储在内置缓存中的值可能会不时到期 我会使用脏标记方法,其中缓存被不时地标记为脏,以指示缓存的值需要刷新,假设您知道何时“时间”。如果不这样做,请考虑一个定时器,指示缓存定期变脏。

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

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

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