【问题标题】:Generating cacheable data exactly once when needed and blocking otherwise?在需要时只生成一次可缓存数据,否则阻塞?
【发布时间】:2012-12-06 05:26:58
【问题描述】:

我正在制作一个很酷的 (imo) T4 模板,这将使缓存变得更加容易。我在制作这个模板时的一个选项是允许“加载一次”类型的功能,尽管我不确定它有多安全。

基本上,我想做这样你就可以做这样的事情:

var post=MyCache.PostsCache.GetOrLockLoad(id, ()=>LoadPost(id));

并且基本上做到了,当必须加载缓存时,它将在PostsCache 上放置一个阻塞锁。这样,其他线程将阻塞,直到 LoadPost() 函数完成。这使得 LoadPost 只会在每次缓存未命中时执行一次。执行此操作的传统方式是 LoadPost 将在缓存为空的任何时候执行,如果在第一次加载缓存之前对它的多个请求可能会执行多次。

这是一个合理的做法,还是因为这种危险或浪费的事情而阻塞其他线程?我在想线程锁定开销大于大多数操作,但也许不是?

有没有人看到过这种事情,这是个好主意还是很危险?

此外,虽然它被设计为在任何缓存和应用程序类型上运行,但它最初的目标是 ASP.Net 的内置缓存机制。

【问题讨论】:

  • Yes 是众所周知的模式,例如由 .NET Lazy 类支持(尽管这本身不是缓存)。当您的示例中的 .LoadPost 会消耗大量资源/根据时间/变异数据返回不同的结果时,这很有用。但是,对于其他情况,我倾向于避免使用它来提高吞吐量。
  • @FuleSnabel 很有趣。这实际上是我第一次看到 Lazy 的东西。

标签: c# asp.net caching concurrency t4


【解决方案1】:

这似乎没问题,因为理论上第一个请求之后的请求只会等待它们自己加载数据所花费的时间。

但它仍然感觉有点不确定 - 如果第一个加载程序线程由于一些可能不会影响其他线程的间歇性问题而被阻止怎么办。感觉让每个线程独立尝试加载会更安全。

它还增加了锁定机制的复杂性和开销。请记住,您执行的锁定越多,您引入的陷入死锁条件的风险就越大(通常)。尽管在您的情况下,只要 LoadPost 方法中没有发生时髦的锁定,这应该不是问题。

考虑到风险,我认为您最好选择非锁定选项。

毕竟,对于任何给定线程,等待时间几乎相同——要么是加载时间,要么是等待第一个线程加载所花费的时间。

当使用非并发选项而不是并发选项时,我总是有点不舒服,尤其是在收益似乎微不足道的情况下。

【讨论】:

  • 好吧,我将允许这两个版本,但我想知道这个雄心勃勃的 load-once 事情是否值得实施。听起来不错,但也很冒险。如果 ASP.Net 的缓存决定不缓存正在存储的对象(我认为这并非不可能,但可能性不大),那么应该做什么也不是微不足道的。
  • 我认为值得一试,即使只是为了好玩,只要你还保留一个非锁定选项以防万一出现问题 :)
猜你喜欢
  • 1970-01-01
  • 2017-06-15
  • 2017-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-12
  • 2015-11-30
  • 1970-01-01
相关资源
最近更新 更多