《高阶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 高阶学习(映射文件深入、延迟加载、缓存、注解开发等)
266 0
Mybatis 高阶学习(映射文件深入、延迟加载、缓存、注解开发等)
|
缓存 Perl
《高阶Perl》——3.8 对象方法里的缓存
本节书摘来自华章计算机《高阶Perl》一书中的第3章,第3.8节,作者(美)Mark Jason Dominus,译 滕家海,更多章节内容可以访问云栖社区“华章计算机”公众号查看。
1426 0
|
缓存 Perl
《高阶Perl》——3.2 内联缓存
本节书摘来自华章计算机《高阶Perl》一书中的第3章,第3.2节,作者(美)Mark Jason Dominus,译 滕家海,更多章节内容可以访问云栖社区“华章计算机”公众号查看。
1441 0
|
缓存 Perl
《高阶Perl》——3.1 缓存修正递归
本节书摘来自华章计算机《高阶Perl》一书中的第3章,第3.1节,作者(美)Mark Jason Dominus,译 滕家海,更多章节内容可以访问云栖社区“华章计算机”公众号查看。
1188 0
|
缓存 Perl
《高阶Perl》——第3章 缓存与记忆术
本节书摘来自华章计算机《高阶Perl》一书中的第3章,作者(美)Mark Jason Dominus,译 滕家海,更多章节内容可以访问云栖社区“华章计算机”公众号查看。
1107 0
|
1月前
|
缓存 NoSQL 安全
【Redis】缓存穿透
【Redis】缓存穿透
30 0
|
1月前
|
缓存 监控 NoSQL
解析Redis缓存雪崩及应对策略
解析Redis缓存雪崩及应对策略
|
1月前
|
存储 缓存 NoSQL
Redis高效缓存:加速应用性能的利器
Redis高效缓存:加速应用性能的利器
|
1月前
|
存储 缓存 Java
【Spring原理高级进阶】有Redis为啥不用?深入剖析 Spring Cache:缓存的工作原理、缓存注解的使用方法与最佳实践
【Spring原理高级进阶】有Redis为啥不用?深入剖析 Spring Cache:缓存的工作原理、缓存注解的使用方法与最佳实践
|
3天前
|
缓存 NoSQL Java
使用Redis进行Java缓存策略设计
【4月更文挑战第16天】在高并发Java应用中,Redis作为缓存中间件提升性能。本文探讨如何使用Redis设计缓存策略。Redis是开源内存数据结构存储系统,支持多种数据结构。Java中常用Redis客户端有Jedis和Lettuce。缓存设计遵循一致性、失效、雪崩、穿透和预热原则。常见缓存模式包括Cache-Aside、Read-Through、Write-Through和Write-Behind。示例展示了使用Jedis实现Cache-Aside模式。优化策略包括分布式锁、缓存预热、随机过期时间、限流和降级,以应对缓存挑战。