首页
/ richfitz/storr项目:使用外部存储实现数据缓存与记忆化

richfitz/storr项目:使用外部存储实现数据缓存与记忆化

2025-06-27 10:05:49作者:袁立春Spencer

概述

richfitz/storr是一个R语言包,提供了键值存储系统的实现。本文将重点介绍其外部存储功能,这是一种强大的机制,允许开发者从外部资源获取数据并自动缓存,同时也可用于实现记忆化(memoization)模式。

外部存储的基本原理

storr的外部存储功能工作流程如下:

  1. 首先在storr中查找键值,如果找到对应的哈希值,则正常返回结果
  2. 如果查找失败,则将键值(和命名空间)传递给"hook"函数,由该函数生成R对象

这种机制类似于记忆化模式,当键值代表一组耗时函数的参数时,可以实现类似记忆化的效果。

实际应用示例:从GitHub获取DESCRIPTION文件

编写hook函数

首先需要创建一个hook函数,该函数接收(key, namespace)参数并返回R对象。以下示例从GitHub获取R包的DESCRIPTION文件:

fetch_hook_gh_description <- function(key, namespace) {
  if (!isTRUE(unname(capabilities("libcurl")))) {
    stop("本示例需要R支持libcurl")
  }
  fmt <- "https://raw.githubusercontent.com/%s/master/DESCRIPTION"
  path <- tempfile("gh_description_")
  on.exit(file.remove(path))
  code <- download.file(sprintf(fmt, key), path, mode = "wb")
  if (code != 0L) {
    stop("文件下载错误")
  }
  as.list(read.dcf(path)[1, ])
}

这个函数:

  1. 检查libcurl支持
  2. 构建GitHub文件URL
  3. 下载到临时文件(使用on.exit确保删除)
  4. 读取并转换DESCRIPTION文件为列表

创建外部storr

使用storr_external函数创建外部存储:

st <- storr::storr_external(storr::driver_environment(),
                           fetch_hook_gh_description)

初始状态下存储为空:

st$list()

但可以通过get方法获取数据:

d <- st$get("richfitz/storr")

获取后数据会被缓存:

identical(st$get("richfitz/storr"), d)

错误处理

当外部资源不可用时,storr会抛出KeyErrorExternal错误:

tryCatch(st$get("richfitz/no_such_repo"),
        KeyErrorExternal = function(e)
          message(sprintf("** 仓库 %s 未找到", e$key)))

持久化存储

如果需要持久化存储,可以导出到RDS存储并处理键值:

st_rds <- st$export(storr::storr_rds(tempfile(), mangle_key = TRUE))
st_rds$list()
st_rds$get("richfitz/storr")$Version

实现记忆化模式

外部存储可以用于实现记忆化功能。考虑一个计算密集型函数:

f <- function(a, b) {
  message(sprintf("计算 f(%.3f, %.3f)", a, b))
  list(a, b)
}

定义参数集和对应的ID:

pars <- data.frame(id = as.character(1:10), a = runif(10), b = runif(10),
                  stringsAsFactors = FALSE)

创建hook函数:

hook <- function(key, namespace) {
  p <- pars[match(key, pars$id), -1]
  f(p$a, p$b)
}

st <- storr::storr_external(storr::driver_environment(), hook)

首次获取会执行计算:

x <- st$get("1")

后续获取则从缓存读取:

identical(st$get("1"), x)

通用记忆化实现

可以基于storr实现通用的记忆化函数:

memoise <- function(f, driver = storr::driver_environment()) {
  force(f)
  st <- storr::storr(driver)
  function(...) {
    key <- digest::digest(list(...))
    tryCatch(
      st$get(key),
      KeyError = function(e) {
        ans <- f(...)
        st$set(key, ans)
        ans
      })
  }
}

使用示例:

f <- function(x) {
  message("计算中...")
  x * 2
}

g <- memoise(f)

# 首次执行
g(1)

# 后续调用从缓存读取
g(1)

总结

richfitz/storr的外部存储功能提供了强大的数据缓存机制,可以:

  1. 从外部资源自动获取并缓存数据
  2. 实现灵活的记忆化模式
  3. 处理复杂的计算缓存需求

通过合理设计hook函数,开发者可以构建出高效的数据处理流程,显著提升R应用的性能。

登录后查看全文
热门项目推荐