【问题标题】:How to set up doSNOW and SOCK cluster with Torque/MOAB scheduler?如何使用 Torque/MOAB 调度程序设置 doSNOW 和 SOCK 集群?
【发布时间】:2013-06-25 02:49:40
【问题描述】:

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)  

【问题讨论】:

    标签: r foreach parallel-processing cluster-computing torque


    【解决方案1】:

    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 执行一个任务,但是如果不依赖snow 和@ 的一些实现细节,将正确数量的分配核心传递给每个worker 并不容易987654329@,具体与doSNOW使用的clusterApplyLB函数的实现有关。当然,如果您碰巧知道每个节点上分配的核心数量相同,这很容易,但如果您想要一个通用的解决方案,那就更难了。

    一个(不那么优雅的)通用解决方案是通过 snow clusterApply 函数将分配的核心数分配给每个工作人员的全局变量:

    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 集群,每个工作人员将使用 8 个内核执行内部 foreach 循环。但由于 R 代码是通用的,它应该做正确的事情,无论通过 qsub 请求的资源如何。

    【讨论】:

    • 这有改变吗?我的系统没有 registerDoMC() 或 registerDoSNOW(),只有 registerDoParallel()。
    • @Dominik 不,它没有改变。 registerDoMC函数定义在doMC包中,依赖于parallel包。
    • 抱歉,我现在看到了。您在 setcores 函数中在哪里设置 cores ?还是我应该把它改成一个数字?
    • @Dominik setcores 函数使用 clusterApply 使用nodes$Freq 中的计数为每个工作人员设置“allocated.cores”变量。我在答案中添加了更多解释以使这一点更清楚(我希望)。
    • @Dominik 当您使用qsub 交互登录并使用-l nodes=1:ppn=4 等选项在一个节点上请求4 个核心时,您应该会看到$PBS_NODEFILE 中列出的本地主机四次。如果您不这样做,您应该与您的系统管理员联系。
    猜你喜欢
    • 2016-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-28
    • 2015-06-11
    • 1970-01-01
    • 2016-05-27
    相关资源
    最近更新 更多