пакет terra возвращает ошибку при попытке запустить параллельные операции
Я работаю с пакетом и пытаюсь переключиться на него, но по непонятным мне причинам не могу воспроизвести ту же операцию, что и при параллельной работе с такими пакетами и
future.apply
. Вот воспроизводимый пример.
library(terra)
r <- rast()
r[] <- 1:ncell(r)
m <- rast()
m[] <- c(rep(1,ncell(m)/5),rep(2,ncell(m)/5),rep(3,ncell(m)/5),rep(4,ncell(m)/5),rep(5,ncell(m)/5))
ms <- separate(m,other=NA)
plot(ms)
mymask <- function(ind){
tipo <- tipo_tav[ind]
mask <- ms[[ind]]
masked <-
terra::mask(
r,
mask
)
richard <- function(x){
k <-0.2
v <-0.3
a <-200
y0 <-2
y <- k/v*x*(1-((x/a)^v))+y0
return(y)
}
pred <- richard(masked)
pred <- clamp(pred,lower=0)
return(pred)
}
#the sequential usage works fine, faster than the `raster` counterpart
system.time(x <- mymask(1))#0.03
#when I try to run my function in parallel I receive an error
plan(multisession,workers=5)
system.time(pred_list <- future_lapply(1:5, FUN = mymask))
Ошибка в .External(list(name = "CppMethod__invoke_notvoid", address = <pointer: (nil)>,: значение NULL как адрес символа.
точно такой же код работает хорошо, если я изменю
rast
с участием
raster
а также
terra::mask
с участием
raster::mask
. См. ниже:
library(raster)
r <- raster(r)
ms <- stack(ms)
mymask <- function(ind){
tipo <- tipo_tav[ind]
mask <- ms[[ind]]
masked <-
raster::mask(
r,
mask
)
richard <- function(x){
k <-0.2
v <-0.3
a <-200
y0 <-2
y <- k/v*x*(1-((x/a)^v))+y0
return(y)
}
pred <- richard(masked)
pred <- clamp(pred,lower=0)
return(pred)
}
#this works fine
system.time(x <- mymask(1))#0.06
#this works too
plan(multisession,workers=5)
system.time(pred_list <- future_lapply(1:5, FUN = mymask))#15.48
Такое же поведение, если я использую
snowfall
вместо
future
library(snowfall)
sfInit(parallel = TRUE, cpus =5)
sfLibrary(terra)
sfExportAll()
system.time(pred_list <- sfLapply(1:5, fun = mymask))
sfStop()
это возвращает ту же ошибку
future_lapply
Почему это происходит? Никогда не видел такой ошибки. Я надеялся воспользоваться более высокой скоростью
terra
но так я застрял.
1 ответ
А
SpatRaster
не может быть сериализован, вы не можете отправить его на параллельные вычислительные узлы. Загляните сюда для более подробного обсуждения.
Вместо этого вы можете (а) отправлять и получать имена файлов, (б) распараллеливать свою настраиваемую функцию, которую вы предоставляете, или
lapp
(c) использовать
cores=n
аргумент (при наличии, например, и
predict
), (г) использовать механизм вроде.
Например, вы можете использовать такую функцию (вариант «а»)
prich <- function(filein, fileout) {
r <- rast(filein)
richard <- function(x) {
k <-0.2
v <-0.3
a <-200
y0 <-2
y <- k/v*x*(1-((x/a)^v))+y0
y[y<0] <- 0
return(y)
}
x <- app(masked, richard, filename=fileout, overwrite=TRUE)
return(TRUE)
}
я использую
app
потому что он гораздо более эффективен для больших растров, поскольку позволяет избежать записи временных файлов для каждой из 10 арифметических операций с помощью SpatRaster. Но, учитывая, что вы хотите распараллелить что-то подобное, я предполагаю, что файлы очень большие.
Или вариант «с»:
richard <- function(x) {
k <-0.2
v <-0.3
a <-200
y0 <-2
y <- k/v*x*(1-((x/a)^v))+y0
y[y<0] <- 0
return(y)
}
x <- app(masked, richard, cores=12)
Ни в том, ни в другом случае я не включил маскировку. Вы можете включить его в вариант «а», но
mask
является интенсивным дисковым вводом-выводом, не требует больших вычислительных ресурсов, поэтому может быть столь же эффективным сделать это за один шаг, а не параллельно.
С участием
wrap
ты мог бы сделать что-то вроде этого
f <- function(w) {
x <- rast(w)
wrap(x)
}
r <- rast(nrow=10, ncol=10, vals=1:100)
x <- f(wrap(r))
x <- rast(x)
Где
f
будет работать параллельно. Это работает только для небольших растров, но это можно сделать с помощью тайлов, и я планирую написать для этого оболочку, чтобы упростить использование.
Будет еще больше, но не задерживайте дыхание.