mclapply() 的性能明显比 lapply() 差。我怎样才能加快速度?

Kar*_*l A 4 parallel-processing r

我是 R 中并行计算的新手,希望使用并行包来加速我的计算(这比下面的示例更复杂)。然而,与通常的 lapply 函数相比,使用 mclapply 函数时的计算时间要长得多。

\n\n

我在笔记本电脑上安装了全新的 Ubuntu 18.04.2 LTS,它具有 7.7 GB 内存和 Intel\xc2\xae Core\xe2\x84\xa2 i7-4500U CPU @ 1.80GHz \xc3\x97 4 处理器。我在 R studio 上运行 R。

\n\n
require(parallel)\n\na <- seq(0, 1, length.out = 110) #data\nb <-  seq(0, 1, length.out = 110)\nc <- replicate(1000, sample(1:100,size=10), simplify=FALSE)\n\nfunction_A <- function(i, j, k) { # some random function to examplify the problem\n  i+ j * pmax(i-k,0) \n}\n\n#running it with mclapply \nptm_mc <- proc.time()  \noutput <- mclapply(1:NROW(c), function(o){ \n  mclapply(1:NROW(a),function(p) function_A(a[p], b, c[[o]]))})\ntime_mclapply <- proc.time() - ptm_mc\n\n# running it with lapply\nptm_lapply <- proc.time()  \noutput <- lapply(1:NROW(c), function(o){\n  lapply(1:NROW(a),function(p) function_A(a[p], b, c[[o]]))})\ntime_lapply <- proc.time() - ptm_lapply\n
Run Code Online (Sandbox Code Playgroud)\n\n

lapply 的结果比 mclapply 结果快得多:

\n\n
 > time_mclapply\n       user      system     elapsed \n      6.030     439.112     148.088 \n > time_lapply\n       user      system     elapsed \n      1.662       0.165       1.827 \n
Run Code Online (Sandbox Code Playgroud)\n\n

为什么我会得到这个结果?是因为我的设置还是常见问题?\n我怎样才能获得实际上比 lapply 结果更快的结果,从而使整个过程更快?

\n\n

更新:\n嵌套循环的两个剩余组合的更新:

\n\n
ptm_mc_OUT <- proc.time()  \noutput <- mclapply(1:NROW(c), function(o){\n  lapply(1:NROW(a),function(p) function_A(a[p], b, c[[o]]))})\n time_mclapply_OUT <- proc.time() - ptm_mc_OUT\n\nptm_mc_IN <- proc.time()  \noutput <- lapply(1:NROW(c), function(o){\n  mclapply(1:NROW(a),function(p) function_A(a[p], b, c[[o]]))})\ntime_mclapply_IN <- proc.time() - ptm_mc_IN\n\n require(dplyr)\ntimes <- rbind(time_mclapply,\n                      time_lapply,\n                      time_mclapply_OUT, \n                      time_mclapply_IN) %>% data.frame()\n\ntimes\n
Run Code Online (Sandbox Code Playgroud)\n\n

这给了我们

\n\n
>times\n                  user.self sys.self elapsed user.child sys.child\ntime_mclapply         0.075    0.081  22.621      1.933    34.266\ntime_lapply           1.070    0.049   1.118      0.000     0.000\ntime_mclapply_OUT     0.064    0.077   0.884      2.539    34.587\ntime_mclapply_IN      1.329   31.843  37.426      5.108    28.879\n
Run Code Online (Sandbox Code Playgroud)\n\n

在另一次运行中我得到了(所以运行时间似乎变化很大,有没有更好的方法来显示它们?)

\n\n
times_lapply\n                   user.self sys.self elapsed user.child sys.child\ntime_mclapply         0.324    0.121   9.108      0.000     0.000\ntime_lapply           1.060    0.049   1.108      0.000     0.000\ntime_mclapply_OUT     0.211    0.092   1.155     10.791    19.632\ntime_mclapply_IN      1.221   22.196  27.089      5.130    23.032\n
Run Code Online (Sandbox Code Playgroud)\n

F. *_*ivé 6

令 N 为机器的线程数。一些建议:

  1. 您不应使用两个级别的并行性,因为您将使用 N^2 线程。

  2. 您应该尝试在外部循环而不是内部循环中进行并行化(因为并行性的开销只会发生一次)。

  3. 您不应该使用所有线程(人们通常使用 N-1 或 N/2)。

当使用 N/2 ( mc.cores = parallel::detectCores() / 2) 时,time_mclapply_OUT速度是 的两倍time_lapply