《高阶Perl》——3.9 持续的缓存

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

3.9 持续的缓存

在离开自动的记忆术的主题之前,将浏览一些外围的技术。将看到一个函数如何被带记忆的版本替代,后者在缓存里存储了返回值,缓存就仅是一个散列变量。

在Perl里,可以使用tie操作符把一个散列变量关联到一个磁盘上的数据库,那么存储在散列的数据会自动写到磁盘上,从散列取回数据实际上是从磁盘取回。把这个功能增加到memoize函数是简单的:

use DB_File;

sub memoize {
  my ($func, $keygen, $file) = @_;
  my %cache;
  if (defined $file) {
    tie %cache => 'DB_File', $file, O_RDWR|O_CREAT, 0666
      or die "Couldn't access cache file $file: $!; aborting";
  }
  my $stub = sub {
    my $key = $keygen ? $keygen->(@_) : join ',', @_;
    $cache{$key} = $func->(@_) unless exists $cache{$key};
    return $cache{$key};
  };
  return $stub;
}

此处增加了一个可选的第三个形参,它是将要接受缓存的数据的磁盘上的文件名。如果提供了,就用tie把散列关联到文件上。注意,如果不使用这个特性,就几乎不付出什么代价。在调用memoize()时会有一次单一的defined()测试。

当缓存散列以这种方式被关联到一个磁盘文件时,缓存就变成持续的了。程序一次运行时在缓存中存储的数据在程序退出以后还保留在文件里,而且在程序下次运行时依然对函数有效。程序逐步把函数替换成磁盘上的一个搜索表。程序员的代价几乎是零,因为不必改变原始函数的任何代码。

如果厌倦了等待查询表完全被占据,就可以强制它。也可以写个小程序,它仅是反复地以不同的参数调用带记忆的函数。可以在周五下午启动它然后回家过周末。当周一回来时,持续的缓存里将有函数预先计算出来的值。当运行实际应用时,对带记忆的函数的调用将几乎是立即返回,因为值已经保存在数据库里了。

同样的,这也可能不是胜利。记住,从记忆术获得的加速由公式hfK决定,K是管理缓存的开销。如果K足够大,它将淹没从公式的hf部分赚到的,就像在3.6节的sub { $_[0] * $_[0] }例子中一样。当把缓存数据存储在一个磁盘文件里时,开销K会数倍于一般情况,因为程序将不得不进行一次操作系统请求以查看磁盘数据库。

另一种也是更加灵活的界面是允许memoize()的用户提供他们自己的关联散列:

sub memoize {
  my ($func, $keygen, $cache) = @_;
  $cache = {} unless defined $cache;
  my $stub = sub {
    my $key = $keygen ? $keygen->(@_) : join ',', @_;
    $cache->{$key} = $func->(@_) unless exists $cache->{$key};
    return $cache->{$key};
  };
  return $stub;
}

这允许用户提供一个以他们喜欢的DBM实现关联到一个磁盘文件的缓存,甚至可以是从没听说过的。他们也可以传递一个普通的散列,那将允许他们在他们希望的时候能清除缓存或让旧的值到期。

相关文章
|
SQL 存储 XML
Mybatis 高阶学习(映射文件深入、延迟加载、缓存、注解开发等)
Mybatis 高阶学习(映射文件深入、延迟加载、缓存、注解开发等)
274 0
Mybatis 高阶学习(映射文件深入、延迟加载、缓存、注解开发等)
|
缓存 Perl
《高阶Perl》——3.8 对象方法里的缓存
本节书摘来自华章计算机《高阶Perl》一书中的第3章,第3.8节,作者(美)Mark Jason Dominus,译 滕家海,更多章节内容可以访问云栖社区“华章计算机”公众号查看。
1445 0
|
缓存 Perl
《高阶Perl》——3.2 内联缓存
本节书摘来自华章计算机《高阶Perl》一书中的第3章,第3.2节,作者(美)Mark Jason Dominus,译 滕家海,更多章节内容可以访问云栖社区“华章计算机”公众号查看。
1455 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自动更新缓存。这些策略有助于保障系统的稳定运行。
302 1
|
6天前
|
存储 消息中间件 缓存
Redis缓存技术详解
【5月更文挑战第6天】Redis是一款高性能内存数据结构存储系统,常用于缓存、消息队列、分布式锁等场景。其特点包括速度快(全内存存储)、丰富数据类型、持久化、发布/订阅、主从复制和分布式锁。优化策略包括选择合适数据类型、设置过期时间、使用Pipeline、开启持久化、监控调优及使用集群。通过这些手段,Redis能为系统提供高效稳定的服务。
|
3天前
|
NoSQL Redis 缓存
【后端面经】【缓存】36|Redis 单线程:为什么 Redis 用单线程而 Memcached 用多线程?
【5月更文挑战第17天】Redis常被称为单线程,但实际上其在处理命令时采用单线程,但在6.0后IO变为多线程。持久化和数据同步等任务由额外线程处理,因此严格来说Redis是多线程的。面试时需理解Redis的IO模型,如epoll和Reactor模式,以及其内存操作带来的高性能。Redis使用epoll进行高效文件描述符管理,实现高性能的网络IO。在讨论Redis与Memcached的线程模型差异时,应强调Redis的单线程模型如何通过内存操作和高效IO实现高性能。
30 7
【后端面经】【缓存】36|Redis 单线程:为什么 Redis 用单线程而 Memcached 用多线程?
|
6天前
|
缓存 NoSQL 关系型数据库
【Redis】Redis 缓存重点解析
【Redis】Redis 缓存重点解析
16 0
|
6天前
|
缓存 NoSQL 关系型数据库
【Redis】Redis作为缓存
【Redis】Redis作为缓存
8 0