为什么parLapplyLB实际上没有平衡负载?

jos*_*kre 14 r rparallel

我正在测试该parLapplyLB()功能,以了解它如何平衡负载.但我没有看到任何平衡发生.例如,

cl <- parallel::makeCluster(2)

system.time(
  parallel::parLapplyLB(cl, 1:4, function(y) {
    if (y == 1) {
      Sys.sleep(3)
    } else {
      Sys.sleep(0.5)
    }}))
##   user  system elapsed 
##  0.004   0.009   3.511 

parallel::stopCluster(cl)
Run Code Online (Sandbox Code Playgroud)

如果它真正平衡了负载,则休眠3秒的第一个作业(作业1)将在第一个节点上,而其他三个作业(作业2:4)将在另一个节点上休眠总共1.5秒.总的来说,系统时间应该只有3秒.

相反,我认为作业1和2被赋予节点1,作业3和4被赋予节点2.这导致总时间为3 + 0.5 = 3.5秒.如果我们运行相同的代码parLapply()代替parLapplyLB(),我们得到相同的系统时间约3.5秒.

我不理解或做错了什么?

Jos*_*ien 14

对于像你这样的任务(就此而言,对于任何我需要并行的任务而言)NEWS并不是真正适合这项工作的工具.要了解其原因,请查看它的实现方式:

* parLapplyLB and parSapplyLB have been fixed to do load balancing
  (dynamic scheduling).  This also means that results of
  computations depending on random number generators will now
  really be non-reproducible, as documented.
Run Code Online (Sandbox Code Playgroud)

问题在于它首先将其作业列表拆分为相等大小的子列表,然后在节点之间分配,每个节点parLapplyLB在其给定的子列表上运行.所以这里,您的第一个节点在第一个和第二个输入上运行作业,而第二个节点使用第三个和第四个输入运行作业.

相反,使用更多功能lapply(),就像你希望的那样:

parLapplyLB
# function (cl = NULL, X, fun, ...) 
# {
#     cl <- defaultCluster(cl)
#     do.call(c, clusterApplyLB(cl, x = splitList(X, length(cl)), 
#         fun = lapply, fun, ...), quote = TRUE)
# }
# <bytecode: 0x000000000f20a7e8>
# <environment: namespace:parallel>

## Have a look at what `splitList()` does:
parallel:::splitList(1:4, 2)
# [[1]]
# [1] 1 2
# 
# [[2]]
# [1] 3 4
Run Code Online (Sandbox Code Playgroud)

  • 这里有用的信息,以及用户定义的parlapplyLB http://detritus.fundacioace.com/pub/books/Oreilly.Parallel.R.Oct.2011.pdf (2认同)