r语言 - knitr 的缓存可以处理指针对象吗?



我使用knitr制作一个使用terra包绘制地图的文档。这是我最小的。rmd文件:

```{r init, echo=FALSE}
library(knitr)
opts_chunk$set(cache=TRUE)
```
```{r maps}
library(terra)
r = rast(matrix(1:12,3,4))
plot(r)
```
```{r test2}
print(r)
plot(r)
```

第一次运行(通过rmarkdown::render(...)),这是有效的,创建一个test_cache文件夹。第二次运行时(没有任何更改)它也运行良好。如果我对块2做一个小的改变(例如添加一个注释)并运行,我得到:

Quitting from lines 14-17 (cache.Rmd) 
Error in .External(list(name = "CppMethod__invoke_notvoid", address = <pointer: (nil)>,  : 
NULL value passed as symbol address

我也有这个从另一个Rmd文件,可能相关:

Quitting from lines 110-115 (work.Rmd) 
Error in x@ptr$readStart() : external pointer is not valid

清除缓存或使用cache=FALSE运行是可行的,但是这样缓存的意义是什么呢?

我认为这是因为r是通过Rcpp分配的一些内存存在的某种引用类,而knitr只是缓存一个引用,所以当它试图读取缓存的版本时,它会得到一个对内存的引用,而内存中没有创建与引用一起去的对象。所以它失败了。

terra栅格对象是这样的:

> str(r)
Formal class 'SpatRaster' [package "terra"] with 1 slot
..@ ptr:Reference class 'Rcpp_SpatRaster' [package "terra"] with 20 fields
.. ..$ depth    : num 0
.. ..$ extent   :Reference class 'Rcpp_SpatExtent' [package "terra"] with 2 fields

> r@ptr
C++ object <0x55ce6fdf2bd0> of class 'SpatRaster' <0x55ce5a6750b0>

是否有办法使knitr缓存工作与这些对象?我知道我可以从缓存中排除这些对象,但我的文档中90%都在处理这些对象,这就是我想使用缓存来加快速度的原因。但是每次我遇到这个错误,我都必须停下来,清空缓存,重新开始,我不知道这段时间是否值得我用缓存加速。


R 4.1.1 with

> packageVersion("knitr")
[1] ‘1.34’
> packageVersion("rmarkdown")
[1] ‘2.11’

terra做一些工作来允许序列化,例如:

library(terra)
f <- system.file("ex/elev.tif", package="terra")
r <- rast(f)
saveRDS(r, "test.rds")
readRDS("test.rds")
[1] "This is a PackedSpatRaster object. Use 'terra::rast()' to unpack it"
readRDS("test.rds") |> rast()
#class       : SpatRaster 
#dimensions  : 90, 95, 1  (nrow, ncol, nlyr)
#resolution  : 0.008333333, 0.008333333  (x, y)
#extent      : 5.741667, 6.533333, 49.44167, 50.19167  (xmin, xmax, ymin, ymax)
#coord. ref. : lon/lat WGS 84 (EPSG:4326) 
#source      : memory 
#name        : elevation 
#min value   :       141 
#max value   :       547 

但是似乎knitr缓存带有"save"到RData文件;在这种情况下,原始对象被存储,当重新加载时将无效。

我认为可能可以通过巧妙地使用钩子函数来解决这个问题;但是,这将是如此复杂,它会破坏缓存的目的。

最新更新