问题描述
我正在使用Rfast
软件包,它将导入软件包RcppZiggurat
。我在Linux群集(Red Hat 6.1)上运行R 3.6.3。这些软件包安装在我的本地目录中,但R安装在系统范围内。
我直接调用Rfast函数(例如colsums()
)时效果很好。但是,当我像下面这样在foreach()
循环中调用它们时(编辑:我添加了代码来注册集群,正如Rui Barradas指出的那样,但这不能解决问题)。
library(Rfast)
library(doParallel)
library(foreach)
cores <- detectCores()
cl <- makeCluster(cores)
registerDoParallel(cl)
A <- matrix(rnorm(1e6),1000,1000)
cm <- foreach(n = 1:4,.packages = 'Rfast') %dopar% colmeans(A)
stopCluster(cl)
unable to load shared object '/home/users/sutd/R/x86_64-pc-linux-gnu-library/3.6/RcppZiggurat/libs/RcppZiggurat.so':
libgsl.so.0: cannot open shared object file: No such file or directory
以某种方式,在直接调用动态库时会被识别,而在foreach()
下调用时则无法识别。
我知道libgsl.so
位于/usr/lib64/
中,因此我在R脚本的开头添加了以下行
Sys.setenv(LD_LIBRARY_PATH=paste("/usr/lib64/",Sys.getenv("LD_LIBRARY_PATH"),sep = ":"))
但这没用。
我也尝试做dyn.load('/usr/lib64/libgsl.so')
,但出现以下错误:
Error in dyn.load("/usr/lib64/libgsl.so") : unable to load shared object '/usr/lib64/libgsl.so':
/usr/lib64/libgsl.so: undefined symbol: cblas_ctrmv
如何在foreach()
并行循环中使用依赖项?
注意
在实际使用案例中,我使用的是遗传算法软件包GA
,并且有GA::ga()
处理foreach()
循环,并且在循环中我在自己的软件包中使用了一个函数调用Rfast
函数。因此,我希望有一个无需修改foreach()
调用的解决方案。
解决方法
以下内容没有问题。与问题中的代码不同,它首先检测可用核心的数量,创建集群并使其对foreach
可用。
library(Rfast)
library(doParallel)
library(foreach)
cores <- detectCores()
cl <- makeCluster(cores)
registerDoParallel(cl)
set.seed(2020)
A <- matrix(rnorm(1e6),1000,1000)
cm <- foreach(n = 1:4,.combine = rbind,.packages = "Rfast") %dopar% {
colmeans(A)
}
stopCluster(cl)
str(cm)
#num [1:4,1:1000] -0.02668 -0.02668 -0.02668 -0.02668 0.00172 ...
# - attr(*,"dimnames")=List of 2
# ..$ : chr [1:4] "result.1" "result.2" "result.3" "result.4"
# ..$ : NULL
,
foreach
软件包非常适合当时。但是,现在,应该仅使用future
进行并行计算,以便进行静态代码分析以正确地导出到工作程序。结果,在future
方法下,不需要向.packages=
注册软件包。此外,future
反映了通常的 R 代码,只是将输出变量设置为listenv
略有变化。例如,我们有:
library("future")
library("listenv")
library("Rfast")
plan(tweak(multiprocess,workers = 2L))
# For all cores,directly use:
# plan(multiprocess)
# Generate matrix once
A <- matrix(rnorm(1e6),1000)
# Setup output
x <- listenv()
# Iterate 4 times
for(i in 1:4) {
# On each core,compute the colmeans()
x[[i]] %<-% {
colmeans(A)
# For better control over function applies,use a namespace call
# e.g. Rfast::colmeans(A)
}
}
# Switch from listenv to list
output <- as.list(x)
,
由于@RuiBarradas和@coatless的回答,我意识到问题不在于foreach()
,因为(1)当我也使用future
运行代码时也出现了问题,并且( 2)当我没有注册集群时,即使使用了错误的调用,它也发生在foreach()
代码中。如果没有注册集群,foreach()
将发出警告并改为以顺序模式运行。但这没有发生。
因此,我意识到问题甚至在foreach()
调用之前就已经发生了。在日志中,它出现在消息Loading package RcppZiggurat
之后。加载此软件包时,肯定出了点问题。
然后,我检查了RcppZiggurat
的依赖关系,发现它依赖于另一个名为RcppGSL
的软件包,该软件包将R和GSL库连接。宾果游戏,这是调用RcppZiggurat时需要libgsl.so.0
的地方。
因此,我制作了一个名为test-gsl.R
的R脚本,该脚本具有以下两行。
library(RcppZiggurat)
print(‘OK’)
现在,我在头节点上运行以下
$ module load R/3.6.3
$ Rscript test-gsl.R
一切正常。会打印出“确定”。
但是,如果我在计算节点上提交作业,此操作将无效。首先,称为test.sh
的PBS脚本如下
### Resources request
#PBS -l select=1:ncpus=1:mem=1GB
### Walltime
#PBS -l walltime=00:01:00
echo Working directory is $PBS_O_WORKDIR
cd $PBS_O_WORKDIR
### Run R
module load R/3.6.3
Rscript test-gsl.R
然后我跑了
qsub test.sh
错误弹出。这意味着我的系统上的计算节点和头节点之间存在某些差异,与程序包无关。我联系了系统管理员,他向我解释说GSL库在默认路径的头节点上可用,但在计算节点上不可用。因此,在我的Shell脚本中,我需要在运行R脚本之前添加module load gsl/2.1
。我测试了一下,一切正常。
该解决方案似乎很简单,但是我对Linux管理了解得很少。经过询问并尝试(而不是盲目地)进行了很多事情之后,我才终于找到了这种解决方案。因此,感谢那些提供帮助的人,以及Mea culpa不能在一开始就准确地描述问题。