0

我可以访问一个具有许多节点的大型计算集群,每个节点都有 >16 个内核,运行 Slurm 20.11.3。我想使用furrr::future_pmap(). 我可以在单个节点上跨多个内核并行化,但我无法找出正确的语法来利用多个节点上的内核。请参阅此相关问题

这是一个可重现的示例,我创建了一个休眠 5 秒并返回开始时间、结束时间和节点名称的函数。

library(furrr)

# Set up parallel processing 
options(mc.cores = 64)
plan(
    list(tweak(multicore, workers = 16),
         tweak(multicore, workers = 16),
         tweak(multicore, workers = 16),
         tweak(multicore, workers = 16))
)


fake_fn <- function(x) {
  t1 <- Sys.time()
  Sys.sleep(x)
  t2 <- Sys.time()
  hn <- system2('hostname', stdout = TRUE)
  data.frame(start=t1, end=t2, hostname=hn)
}

stuff <- data.frame(x = rep(5, 64))

output <- future_pmap_dfr(stuff, function(x) fake_fn(x))

我以salloc --nodes=4 --ntasks=64交互方式使用并运行上述 R 脚本来运行该作业。

该脚本在大约 20 秒内运行,并为所有行返回相同的主机名,这表明它在一个节点上同时运行 16 次迭代,而不是按预期在 4 个节点上同时运行 64 次迭代。我应该如何更改plan()语法以便可以利用多个节点?

编辑:我还尝试了其他一些事情:

  • 我替换multicoremultisession,但没有看到输出有任何差异。
  • 我替换了plan(list(...))plan(cluster(workers = availableWorkers())但它只是挂起。
4

1 回答 1

1
options(mc.cores = 64)
plan(
    list(tweak(multicore, workers = 16),
         tweak(multicore, workers = 16),
         tweak(multicore, workers = 16),
         tweak(multicore, workers = 16))
)

抱歉,这不起作用。当您指定这样的未来策略列表时,您正在指定应该在嵌套的未来调用中使用什么。在您的future_pmap_dfr()示例中,将仅使用此列表中的第一级。其他三个级别从不使用。有关更多详细信息,请参阅https://future.futureverse.org/articles/future-3-topologies.html


我将 ... 替换为 plan(clu​​ster(workers = availableWorkers()) ...

是的,

plan(cluster, workers = availableWorkers())

这相当于默认值,

plan(cluster)

是这里的正确尝试。

...但它只是挂起。

这里可能发生了两件事。第一个,是工人一个一个的设置。因此,如果您有很多,则需要很长时间才能plan()完成。我建议您只尝试两个工人来确认它是否有效。你也可以打开调试输出看看会发生什么,即

library(future)
options(parallelly.debug = TRUE)
plan(cluster)

其次,跨节点使用 PSOCK 集群需要您对这些并行工作人员具有 SSH 访问权限。并非所有 HPC 环境都支持这一点,例如它们可能会阻止用户通过 SSH:ing 进入计算节点。这也可能是你正在经历的。如上所述,打开调试以找出它停止的位置。

现在,即使您设法使这项工作正常进行,您也将面临 R 中的限制,即您最多只能拥有 125 个并行工作程序,但通常会少一些。您可以在https://github.com/HenrikBengtsson/Wishlist-for-R/issues/28中阅读有关此限制的更多信息。它还表明,可以调整 R 源代码并重新编译以将此限制增加到数千。


上述方法的替代方法是使用future.batchtools

plan(future.batchtools::batchtools_slurm, workers = availableCores())

这将导致其中的任务future_pmap_dfr()将通过n = availableCores()Slurm 作业解决。当然,这伴随着调度程序的额外开销,例如排队、启动、运行、完成和读回数据。

顺便说一句,讨论这些事情的最佳地点是https://github.com/HenrikBengtsson/future/discussions

于 2022-02-04T00:40:27.930 回答