R Knitr 为什么通过复制使缓存失效?

R Knitr Why is the cache invalidated by copying?

问题

似乎通过将相关文件(.rmd 脚本和缓存目录)复制到另一台计算机,knitr 缓存变得无效。

  1. 为什么会这样
  2. 我该如何解决这个问题?

详情

我在两台计算机上进行各种冗长的计算。我认为以下程序可行:

  1. 在机器 A 上编写报告的第一个版本。(包括一些冗长的计算)
  2. 将创建的文件,即脚本和缓存目录复制到机器B。
  3. 继续在机器 B 上编辑报告(无需重新计算,因为所有内容都已缓存)。

这不起作用,将文件复制到 B 后,“knit”会执行完整的重新计算。甚至在执行任何脚本编辑之前都是这种情况,即仅从 A 复制到 B 的行为似乎足以使缓存无效。

为什么要对 B 执行完整的重新计算?据我了解,缓存机制归结为创建和比较哈希。本来希望复制后hash不变。

还有什么我应该另外复制的吗?或者有什么其他方法可以使上述过程有效吗?

例子

任何简单的脚本都可以作为示例,例如下面的脚本:

```{r setup, include=FALSE}
knitr::opts_chunk$set(cache = TRUE)
```
Bla Bla
```{r test}
tmp = sort(runif(1e7))
```

我不知道为什么会发生这种情况的细节,但解决方法很简单:将值显式保存到文件,然后读回它们。您可以使用

saveRDS(x, "x.rds")

将变量x保存到名为x.rds的文件中,然后

x <- readRDS("x.rds")

重新读入。如果你想变得更有趣,你可以使用 file.exists("x.rds") 检查 x.rds 是否存在,然后进行完整计算,如果是 saveRDS returns FALSE,否则直接读取数据。

编辑添加:如果你真的想知道第一个问题的答案,一种可能的方法是将文件夹从第二台计算机复制回第一台,然后看看它是否在那里工作。如果不是,请对原始目录和两次复制的目录进行二进制比较,看看发生了什么变化。

如果确实有效,可能只是两台计算机上的 RNGkind() 设置不同:保存错误 sample.kind = "Rounding" 是很常见的。不确定缓存是否会使用它。或者可能是不同的包版本或 R 版本:当我更新时 knitr 缓存无效。

更多补充:

如果您想查看发生了什么变化,请在 digest::digest 函数上打开调试,然后调用 knitr::knit("src.Rmd")digest() 为每个缓存块调用,并在其 object 参数中传递一个大列表。如果列表相同,它应该 return 相同的散列值,因此您需要保存这些对象,并在两台计算机之间进行比较。例如,对于上面的玩具示例,我将其传递为 object:

list(eval = TRUE, echo = TRUE, results = "markup", tidy = FALSE, 
    tidy.opts = NULL, collapse = FALSE, prompt = FALSE, comment = "##", 
    highlight = TRUE, size = "normalsize", background = "#F7F7F7", 
    strip.white = TRUE, cache = 3, cache.path = "cache/", cache.vars = NULL, 
    cache.lazy = TRUE, dependson = NULL, autodep = FALSE, fig.keep = "high", 
    fig.show = "asis", fig.align = "default", fig.path = "figure/", 
    dev = "png", dev.args = NULL, dpi = 72, fig.ext = NULL, fig.width = 7, 
    fig.height = 7, fig.env = "figure", fig.cap = NULL, fig.scap = NULL, 
    fig.lp = "fig:", fig.subcap = NULL, fig.pos = "", out.width = NULL, 
    out.height = NULL, out.extra = NULL, fig.retina = 1, external = TRUE, 
    sanitize = FALSE, interval = 1, aniopts = "controls,loop", 
    warning = TRUE, error = TRUE, message = TRUE, render = NULL, 
    ref.label = NULL, child = NULL, engine = "R", split = FALSE, 
    purl = TRUE, label = "test", code = "tmp = sort(runif(1e7))", 
    75L)