在Slurm集群并行运行R代码时仅单个节点工作的问题求助
问题原因
你当前的R代码中,makeCluster(80)默认会在提交作业的单个节点上创建80个本地进程,但该节点仅配备40核,因此实际只能利用这40核,且所有进程不会分发到Slurm分配的第二个节点。这是因为parallel::makeCluster默认使用FORK类型(仅支持本地节点),且未指定远程节点列表。
解决方案
要实现跨2个节点利用80核,需要让R明确知道Slurm分配的所有节点,并基于这些节点创建跨节点的PSOCK集群(支持远程节点通信)。
步骤1:调整Slurm作业脚本(可选但更清晰)
明确指定每个节点的任务数,避免歧义:
#!/bin/bash #SBATCH --job-name Cores.R #SBATCH --partition warshel-cpu #SBATCH --nodes=2 #SBATCH --ntasks-per-node=40 # 每个节点分配40核 #SBATCH --time 1-00:00:00 #SBATCH --output /path/to/your/output.log #SBATCH --error /path/to/your/error.log cd /path/to/your/workdir R --vanilla --slave < Cores.R
步骤2:修改R代码,创建跨节点集群
通过Slurm环境变量获取分配的节点列表,基于这些节点创建PSOCK集群:
rm(list = ls()) library(parallel) fun <- function(x){ return(x + 1) } # 获取Slurm分配的所有节点主机名 nodes <- system("scontrol show hostnames $SLURM_NODELIST", intern = TRUE) # 每个节点启动40个worker(匹配节点核数) spec <- rep(nodes, each = 40) # 创建跨节点PSOCK集群(依赖节点间SSH免密,Slurm集群通常已配置) cl <- makeCluster(spec, type = "PSOCK") ptm <- proc.time() system.time({ res <- parLapply(cl, 1:50000000, fun) }) print(proc.time() - ptm) stopCluster(cl)
替代方案:使用future包(更简洁的现代并行方式)
future包对集群环境的适配性更好,代码更简洁:
rm(list = ls()) library(future) library(future.apply) fun <- function(x){ return(x + 1) } # 获取节点列表并配置集群计划 nodes <- system("scontrol show hostnames $SLURM_NODELIST", intern = TRUE) spec <- rep(nodes, each = 40) plan(cluster, workers = spec) ptm <- proc.time() res <- future_lapply(1:50000000, fun) print(proc.time() - ptm)
关键说明
- PSOCK类型集群通过SSH在远程节点启动worker,Slurm集群通常已配置节点间免密SSH,无需额外操作。
- 避免使用
FORK类型(makeCluster(80, type="FORK")),该类型仅能在本地节点创建进程,无法跨节点。
内容的提问来源于stack exchange,提问作者qwq
相关产品推荐
相关产品推荐

