1.想一想,如果我们有一个操作是非常耗时,而结果是不变的,或者结果变化的程度不大且可以延时出现(结果),那么我们没有必要重复性的去做这件事情
或者在一定时间将结果进行复用,使用画画来看看
我们假设黑线上的红点是原本要访问的时间点,然而但每次结果的差异不大时我们就可以复用上一次的结果,例子博客发表的帖数不到5以上就不显示,所以我们画出绿色的间隔表示,t1,t2,t3,t4,t5表示缓存间隔,也就是根据设置我们可以把t1的结果用在t2上,或者t3用在t5上
这样就减少cpu的负担
实际用处,例如我们有个商城,每秒有500个用户点击,每次点击即读取数据库,然而在500次在一秒内的结果是差异不大的,那么我们就可以归为一次就够了,这样就大大减少cpu的负担
添加依赖
name:="demo7"
resolvers += "spray repo" at "http://repo.spray.io"
libraryDependencies ++= Seq(
"com.typesafe.akka" % "akka-actor_2.10" % "2.3.12" withSources() withJavadoc(),
"io.spray" % "spray-util" % "1.2.1" withSources() withJavadoc(),
"io.spray" % "spray-caching" % "1.2.1" withSources() withJavadoc(),
"org.scalatest" % "scalatest_2.10" % "2.2.2" withSources() withJavadoc(),
"org.specs2" %% "specs2" % "1.12.3" withSources() withJavadoc(),
"com.googlecode.concurrentlinkedhashmap" % "concurrentlinkedhashmap-lru" % "1.4" withSources() withJavadoc()
)
1.假设我们有个运算是非常复杂的,我们想要一定程度上复用他,为社么叫一定程度呢?因为我们用key来标记,想要复用他就往内存找出这个key对应的值
def expensiveOp(): Double = new util.Random().nextDouble()
Actor相关
val system = ActorSystem();
import system.dispatcher
2.创建结果类型对应的cache
val cache: Cache[Double] = LruCache()
3.
def cacheOp[T](key: T): Future[Double] = cache.apply(key) {
expensiveOp()
}
注意这里的key即对应结果的,如果key找不到就再次运算expensiveOp
测试
class AppTest extends Specification{
"cacheing operation" should {
"""cacheOp must be Equal""" in{
val a = Demo.cacheOp("foo").await
val b = Demo.cacheOp("foo").await
a must_==(b)
}
"""cacheOp must be NoEqual""" in{
val a = Demo.cacheOp("foo1").await
val b = Demo.cacheOp("foo2").await
a must_!=(b)
}
}
}
觉得很不错吧,当然我们是使用LruCache创建的该策略是SimpleLruCache
<p> def apply[V](maxCapacity: Int = 500,
initialCapacity: Int = 16,
timeToLive: Duration = Duration.Inf,
timeToIdle: Duration = Duration.Inf): Cache[V] = {
//#
def check(dur: Duration, name: String) =
require(dur != Duration.Zero,
s"Behavior of LruCache.apply changed: Duration.Zero not allowed any more for $name parameter. To disable " +
"expiration use Duration.Inf instead of Duration.Zero")
// migration help
check(timeToLive, "timeToLive")
check(timeToIdle, "timeToIdle")</p><p> if (timeToLive.isFinite() || timeToIdle.isFinite())
new ExpiringLruCache[V](maxCapacity, initialCapacity, timeToLive, timeToIdle)
else
new SimpleLruCache[V](maxCapacity, initialCapacity)
}</p>
也就是时间不限制的!就是我们key对应的值永久存在内存中的!这样对于一些情况不不好的,例如当该操作是数据库读取的时候,我们要抛弃一些时间点的数据,如5分钟读取前的数据就不要了,那么我们可以通过另一个策略ExpiringLruCache,具体的就自已配置了