在 R foreach() 下并行 运行 时无法识别动态库依赖项
Dynamic library dependencies not recognized when run in parallel under R foreach()
我正在使用 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, 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) 当我 运行 使用 [=15] 的代码时出现问题=] 也是,并且 (2) 当我没有注册集群时,即使调用错误,它也会与 foreach()
代码一起出现。当没有集群注册时,foreach()
将抛出警告并 运行s 改为顺序模式。但那并没有发生。
因此,我意识到问题一定是在 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
一切正常。打印了‘OK’。
但是如果我在计算节点上提交作业,这不起作用。一、PBS脚本,名为test.sh
,如下
### 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 脚本中,我需要在 运行 之前添加 module load gsl/2.1
我的 R 脚本。我测试了一下,一切正常。
这个解决方案看起来很简单,但我对 Linux 管理知之甚少,无法实现它。只有在四处询问并尝试(相当盲目地)很多事情之后,我才终于找到了这个解决方案。所以感谢那些提供帮助的人,并感谢在开始时无法准确描述问题。
我正在使用 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, 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) 当我 运行 使用 [=15] 的代码时出现问题=] 也是,并且 (2) 当我没有注册集群时,即使调用错误,它也会与 foreach()
代码一起出现。当没有集群注册时,foreach()
将抛出警告并 运行s 改为顺序模式。但那并没有发生。
因此,我意识到问题一定是在 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
一切正常。打印了‘OK’。
但是如果我在计算节点上提交作业,这不起作用。一、PBS脚本,名为test.sh
,如下
### 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 脚本中,我需要在 运行 之前添加 module load gsl/2.1
我的 R 脚本。我测试了一下,一切正常。
这个解决方案看起来很简单,但我对 Linux 管理知之甚少,无法实现它。只有在四处询问并尝试(相当盲目地)很多事情之后,我才终于找到了这个解决方案。所以感谢那些提供帮助的人,并感谢在开始时无法准确描述问题。