如何编写用于并行化的高效嵌套函数?

How to write efficient nested functions for parallelization?

我有一个包含两个分组变量 classgroup 的数据框。对于每个 class,我每组都有一个绘图任务。 大多数情况下,我每个 class 2 个级别和每个 group.

500 个级别

我正在使用 parallel 包进行并行化,并使用 mclapply 函数通过 classgroup 级别进行迭代。

我想知道哪种是编写迭代的最佳方式。我想我有两个选择:

  1. 运行 class 变量的并行化。
  2. 运行 group 变量的并行化。

我的电脑有 3 个核心用于 R 会话,通常,为我的操作系统保留第 4 个核心。我想知道如果对具有 2 个级别的 class 变量执行并行化,将永远不会使用第 3 个内核,所以我认为确保所有 3 个内核都将工作 运行 并行化会更有效对于 group 变量。我已经写了一些速度测试来确定哪个是最好的方法:

library(microbenchmark)
library(parallel)

f = function(class, group, A, B) {
  
  mclapply(seq(class), mc.cores = A, function(z) {
    mclapply(seq(group), mc.cores = B, function(c) {
      ifelse(class == 1, 'plotA', 'plotB')
    })
  })
  
}

class = 2
group = 500

microbenchmark(
  up = f(class, group, 3, 1),
  nest = f(class, group, 1, 3),
  times = 50L
)

Unit: milliseconds
 expr       min        lq     mean    median       uq      max neval
   up  6.751193  7.897118 10.89985  9.769894 12.26880 26.87811    50
 nest 16.584382 18.999863 25.54437 22.293591 28.60268 63.49878    50

结果告诉我应该对 class 而不是 group 变量使用并行化。

总的来说,我总是应该编写一个核心函数,然后调用它进行并行化。我认为这样,我的代码会比编写具有并行化功能的嵌套函数更简单或简化。

使用ifelse条件是因为之前用来准备绘图任务数据的代码对于两个class级别来说或多或少都是冗余的,所以我认为它会更行编码高效地编写一个较长的函数来检查使用了哪个 class 级别,而不是将此函数“拆分”为两个较短的函数。

编写此类代码的最佳做法是什么?。我接缝很清楚,但因为我不是专家数据科学家,所以我想知道你的工作方法。

This threat就是围绕这个问题。但我认为我的问题是针对两种观点的:

  • 代码美观清晰
  • 速度性能

谢谢

你刚才问过这个问题,但我会尝试回答,以防其他人有同样的疑问。首先,我喜欢先拆分我的任务,然后循环遍历每个部分。这让我可以更好地控制流程。

parts <- split(df, c(df$class, df$group))
mclapply(parts, some_function)

其次,将任务分配到多个内核会占用大量计算开销,并且会抵消您通过并行化脚本获得的任何收益。在这里,mclapply 将作业拆分为您拥有的任意多个节点,并执行一次 fork。这比嵌套两个 mclapply 循环更有效。