在 R foreach() 下并行运行时无法识别动态库依赖项
Posted
技术标签:
【中文标题】在 R foreach() 下并行运行时无法识别动态库依赖项【英文标题】:Dynamic library dependencies not recognized when run in parallel under R foreach() 【发布时间】:2021-02-09 13:03:18 【问题描述】:我正在使用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
,并拥有处理foreach()
循环的GA::ga()
,在循环中我使用我自己的包中的一个函数,它调用Rfast
职能。所以我希望有一个解决方案,我不必修改foreach()
调用。
【问题讨论】:
我也尝试过export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib64/
,并在foreach()
调用中添加了.packages = c('Rfast', 'RcppZiggurat')
。都失败了。
您是否尝试过重新安装软件包Rfast
?
你为什么要在as a GitHub issue 和这里重复发帖?
对不起,@DirkEddelbuettel。我在虚弱和沮丧的时刻发布了 GitHub 问题。当我在一个月内提交论文时,我迫切需要代码才能工作。几天来我一直在尝试解决依赖关系,但它们只是一个接一个地弹出,我想放弃。但是在发布 GitHub 问题几个小时后,冷静下来后,我做了一些测试,意识到这是因为并行处理。所以我认为在这里发帖是合适的。我没有意识到交叉发布是不合适的。学过的知识。我道歉。
@RuiBarradas 是的,我尝试重新安装,首先只是RcppZiggurat
,然后是Rfast
,但并没有解决问题。
【参考方案1】:
以下工作没有问题。与问题中的代码不同,它首先检测可用内核的数量,创建一个集群并将其提供给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()
是从GA::ga()
调用的,它已经自己进行集群注册。在 Windows 上我不需要单独注册,代码就可以了。当我移植到 Linux 时,它失败了。
如果您的问题 (@Drumy) 是 GA::ga
没有成功导出库(我认为这是包中的错误),您是否尝试过 1) 更新包? 2)覆盖函数定义,手动添加导出。这可以使用函数定义的复制粘贴或使用edit(GA::ga)
手动完成。函数本身只有 1 次对 foreach
的调用,因此很容易修复。
谢谢奥利弗。是的,GA 包已更新(实际上是全新安装)。但我认为不只是GA,因为按照上面Rui的代码手动导出也不起作用。【参考方案2】:
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)
【讨论】:
感谢您的建议。我刚刚尝试了您的代码,但仍然出现同样的错误。 @Drumy 我删除了futureOf()
部分。如果你运行上面的代码,会出现什么错误?【参考方案3】:
感谢@RuiBarradas 和@coatless 的回答,我意识到问题不在于foreach()
,因为(1)问题发生在我使用future
运行代码时,并且(2)它发生了使用foreach()
代码,即使调用错误,但我没有注册集群。当没有注册集群时,foreach()
将抛出警告并改为以顺序模式运行。但这并没有发生。
因此,我意识到问题肯定在foreach()
调用之前就已经发生了。在日志中,它出现在消息 Loading package RcppZiggurat
之后。加载此包时一定有问题。
然后我检查了RcppZiggurat
的依赖关系,发现它依赖于另一个名为RcppGSL
的包,它连接了R和GSL库。 Bingo,这就是调用 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 脚本中,我需要在运行我的 R 脚本之前添加module load gsl/2.1
。我对此进行了测试,一切正常。
解决方案似乎很简单,但我对 Linux 管理知之甚少,无法实现它。只有在四处询问并尝试(相当盲目地)许多事情之后,我才最终得出了这个解决方案。所以感谢那些提供帮助的人,以及一开始无法准确描述问题的过失。
【讨论】:
以上是关于在 R foreach() 下并行运行时无法识别动态库依赖项的主要内容,如果未能解决你的问题,请参考以下文章
使用 foreach 进行并行处理时出错:“找不到函数“%dopar%””
与 foreach 并行预测 nnet 输出时 R 内存爆炸