【问题标题】:How to write efficient nested functions for parallelization?如何为并行化编写高效的嵌套函数?
【发布时间】:2020-03-07 19:26:50
【问题描述】:

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

我使用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 解决了这个问题。但我认为我的问题是针对两种观点的:

  • 代码美观清晰
  • 速度表现

谢谢

【问题讨论】:

    标签: r parallel-processing mclapply


    【解决方案1】:

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-12-28
      • 1970-01-01
      • 1970-01-01
      • 2020-06-24
      • 1970-01-01
      • 2023-04-10
      • 2022-01-06
      相关资源
      最近更新 更多