r - 如何使用 Torque/MOAB 调度程序设置 doSNOW 和 SOCK 集群?

标签 r foreach parallel-processing cluster-computing torque

继续this question (https://stackoverflow.com/questions/17222942/allow-foreach-workers-to-register-and-distribute-sub-tasks-to-other-workers) , 将 doSNOW 和 SOCK 集群连接到 Torque/MOAB 调度程序的最佳实践是什么,以避免处理外部并行循环的某些部分代码的内部并行循环中的处理器关联?

来自 the Steve's answer to that question ,不影响调度程序的基线代码可以是:

library(doSNOW)
hosts <- c('host-1', 'host-2')
cl <- makeSOCKcluster(hosts)
registerDoSNOW(cl)
r <- foreach(i=1:4, .packages='doMC') %dopar% {
  registerDoMC(2)
  foreach(j=1:8, .combine='c') %dopar% {
    i * j
  }
}
stopCluster(cl)  

最佳答案

Torque 总是会创建一个文件,其中包含已由 Moab 分配给您的作业的节点名称,并通过 PBS_NODEFILE 环境变量将该文件的路径传递给您的作业。节点名称可能会被多次列出,以表明它为该节点上的作业分配了多个核心。在这种情况下,我们希望为 PBS_NODEFILE 中的每个唯一节点名称启动一个集群工作程序,但要跟踪每个节点上分配的核心数,以便我们可以在以下情况下指定正确的核心数注册 doMC

这是一个函数,它读取 PBS_NODEFILE 并返回一个包含已分配节点信息的数据帧:

getnodes <- function() {
  f <- Sys.getenv('PBS_NODEFILE')
  x <- if (nzchar(f)) readLines(f) else rep('localhost', 3)
  as.data.frame(table(x), stringsAsFactors=FALSE)
}

返回的数据框包含一个名为“x”的节点名称列和一个名为“Freq”的对应核心计数列。

这使得创建和注册一个 SOCK 集群变得简单,每个节点都有一个工作人员:

nodes <- getnodes()
cl <- makeSOCKcluster(nodes$x)
registerDoSNOW(cl)

我们现在可以很容易地执行一个 foreach 循环,每个 worker 一个任务,但是要将正确数量的分配核心传递给每个 worker 并不容易,而不依赖于两者的一些实现细节snowdoSNOW,具体与doSNOW 使用的clusterApplyLB 函数的实现有关。当然,如果您碰巧知道每个节点上分配的核心数量相同,这很容易,但如果您想要问题的通用解决方案,那就更难了。

一个(不太优雅)的通用解决方案是通过 snow clusterApply 函数将已分配核心的数量分配给每个 worker 上的全局变量:

setcores <- function(cl, nodes) {
  f <- function(cores) assign('allocated.cores', cores, pos=.GlobalEnv)
  clusterApply(cl, nodes$Freq, f)
}
setcores(cl, nodes)

这保证了每个 worker 上的“allocated.cores”变量的值等于该节点在 PBS_NODEFILE 中出现的次数。

现在我们可以在注册 doMC 时使用那个全局变量:

r <- foreach(i=seq_along(nodes$x), .packages='doMC') %dopar% {
  registerDoMC(allocated.cores)
  foreach(j=1:allocated.cores, .combine='c') %dopar% {
    i * j
  }
}

这是一个可用于执行此 R 脚本的示例作业脚本:

#!/bin/sh
#PBS -l nodes=4:ppn=8
cd "$PBS_O_WORKDIR"
R --slave -f hybridSOCK.R

当通过 qsub 命令提交时,R 脚本将创建一个包含四个工作人员的 SOCK 集群,每个工作人员将执行内部 foreach 循环,使用8 个核心。但由于 R 代码是通用的,因此无论通过 qsub 请求的资源如何,它都应该做正确的事情。

关于r - 如何使用 Torque/MOAB 调度程序设置 doSNOW 和 SOCK 集群?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17288379/

相关文章:

php - Laravel foreach in 方法仅返回最后一个结果

c++ - RcppParallel 中如何调用自定义函数?

c# - 为什么使用两个任务执行两个长计算会降低性能?

c - MPI_Gather() 将中心元素放入全局矩阵中

r - R中如何按国家/地区格式化日期?

r - data.frame 定义中的赋值

R - 定位两条曲线的交点

r - 将两个嵌套 tibble 变量相乘

javascript - 当 ForEach 循环中的每个异步函数都已处理完毕时返回 Promise 结尾 [Javascript/Typescript]

arrays - Powershell 仅在不存在时添加到数组