《高阶Perl》——3.2 内联缓存

简介: 本节书摘来自华章计算机《高阶Perl》一书中的第3章,第3.2节,作者(美)Mark Jason Dominus,译 滕家海,更多章节内容可以访问云栖社区“华章计算机”公众号查看。

3.2 内联缓存

给一个函数添加缓存的最直接的方式就是给函数一个私有的散列。在这个例子里,可以使用一个数组代替散列,因为fib()的参数总是一个非负整数。但是一般需要使用一个散列,那么将会看到:

### Code Library: fib-cached
# Compute the number of pairs of rabbits alive in month n
{ my %cache;
  sub fib {
    my ($month) = @_;
    unless (exists $cache{$month}) {
      if ($month < 2) { $cache{$month} = $month }
      else {
        $cache{$month} = fib($month-1) + fib($month-2);
      }
    }
    return $cache{$month};
  }
}

这里的fib得到和之前一样的参数。但不是立即进入递归的Fibonacci数列计算,它先检查缓存。缓存是一个散列,%cache。当函数计算一个Fibonacci数fib($month),它将把这个值存入$cache{$month}。随后对fib()的调用将检查缓存散列中是否有这个值。这就是exists $cache{$month}测试的目的。如果缓存元素不存在,即函数此前没有为这个指定的$month调用过。在unless块中的代码就是一般的Fibonacci计算,包括如果需要的递归调用。然而,一旦函数算出了答案,它不是立即返回它,而是把数值插入缓存散列的合适位置。例如,当$month < 2是真,$cache{$month} = 1负责在缓存里占位。

在函数的末尾,return $cache{$month}返回缓存了的值,不管这个值是函数刚才插入的或者一开始就在那里的。

有了这些改变,fib函数变快了。在第1章看到的过度递归的问题简单地消失了。问题是由结果的重复的再次计算引起的,添加了缓存行为阻止了任何再次计算的出现。当函数尝试再次计算一个已经被计算过的结果时,它会立即从缓存里得到值。

3.2.1 静态变量

为什么%cache在fib的外面而不是里面,为什么有一个空的花括号包住%cache和fib?

如果%cache是在fib里面声明的,如下:

sub fib {
  my %cache;
  ...
}

那么缓存不会工作的,因为每次调用fib时,就会生成一个新的%cache变量,并在fib返回时抛弃。通过在任何函数的外面声明%cache,告诉Perl我们只想要一个%cache实例,它在程序首次编译时生成并且仅在程序结束时销毁。这就使得%cache可以积累数值并在调用fib前后保留它。一个类似%cache的在所有函数外部声明的变量称为一个静态变量(static variable),因为它的值保持不变,除非显式改变,也因为C语言的一个类似功能是由关键词static激活的。

%cache是由my声明的,所以它是词法域的。默认状态,它的作用域将持续到文件的结束。如果在fib后面定义了任何函数,它们也可以看到和修改缓存。但这不是我们想要的,我们想要缓存完全是fib私有的。把%cache和fib包在一个隔开的块中能达到这个目的。%cache的作用域仅延伸到此块的结束,这里面只有fib没别的了。

相关文章
|
8月前
|
缓存 Java
JVM内联缓存
JVM内联缓存
61 0
|
存储 缓存 索引
图解 Google V8 # 16:V8是怎么通过内联缓存来提升函数执行效率的?
图解 Google V8 # 16:V8是怎么通过内联缓存来提升函数执行效率的?
133 0
图解 Google V8 # 16:V8是怎么通过内联缓存来提升函数执行效率的?
|
SQL 存储 XML
Mybatis 高阶学习(映射文件深入、延迟加载、缓存、注解开发等)
Mybatis 高阶学习(映射文件深入、延迟加载、缓存、注解开发等)
274 0
Mybatis 高阶学习(映射文件深入、延迟加载、缓存、注解开发等)
|
存储 Web App开发 缓存
【JavaScript Weekly #399】JavaScript引擎基础(上):形态和内联缓存
本文描述 JavaScript 引擎中通用的一些关键的基础知识——不仅仅是 V8。作为一名 JavaScript 开发人员,对 JavaScript 引擎的工作原理深入了解一下有助于你更好的编写代码。
184 0
|
存储 缓存 程序员
《高阶Perl》——3.9 持续的缓存
本节书摘来自华章计算机《高阶Perl》一书中的第3章,第3.9节,作者(美)Mark Jason Dominus,译 滕家海,更多章节内容可以访问云栖社区“华章计算机”公众号查看。
1368 0
|
缓存 Perl
《高阶Perl》——3.8 对象方法里的缓存
本节书摘来自华章计算机《高阶Perl》一书中的第3章,第3.8节,作者(美)Mark Jason Dominus,译 滕家海,更多章节内容可以访问云栖社区“华章计算机”公众号查看。
1445 0
|
缓存 Perl
《高阶Perl》——3.1 缓存修正递归
本节书摘来自华章计算机《高阶Perl》一书中的第3章,第3.1节,作者(美)Mark Jason Dominus,译 滕家海,更多章节内容可以访问云栖社区“华章计算机”公众号查看。
1202 0
|
缓存 Perl
《高阶Perl》——第3章 缓存与记忆术
本节书摘来自华章计算机《高阶Perl》一书中的第3章,作者(美)Mark Jason Dominus,译 滕家海,更多章节内容可以访问云栖社区“华章计算机”公众号查看。
1120 0
|
6天前
|
消息中间件 缓存 NoSQL
Redis经典问题:缓存雪崩
本文介绍了Redis缓存雪崩问题及其解决方案。缓存雪崩是指大量缓存同一时间失效,导致请求涌入数据库,可能造成系统崩溃。解决方法包括:1) 使用Redis主从复制和哨兵机制提高高可用性;2) 结合本地ehcache缓存和Hystrix限流降级策略;3) 设置随机过期时间避免同一时刻大量缓存失效;4) 使用缓存标记策略,在标记失效时更新数据缓存;5) 实施多级缓存策略,如一级缓存失效时由二级缓存更新;6) 通过第三方插件如RocketMQ自动更新缓存。这些策略有助于保障系统的稳定运行。
291 1
|
6天前
|
存储 消息中间件 缓存
Redis缓存技术详解
【5月更文挑战第6天】Redis是一款高性能内存数据结构存储系统,常用于缓存、消息队列、分布式锁等场景。其特点包括速度快(全内存存储)、丰富数据类型、持久化、发布/订阅、主从复制和分布式锁。优化策略包括选择合适数据类型、设置过期时间、使用Pipeline、开启持久化、监控调优及使用集群。通过这些手段,Redis能为系统提供高效稳定的服务。