parApply()是否将矩阵除然后处理每个矩阵?

时间:2019-06-26 12:00:03

标签: r parallel-processing apply rparallel

假设我有一个parApply()通话,如下:

cl <- makeCluster("FORK", 5)
parApply(cl = cl, X = my.mat, MARGIN = 1, FUN = myFun)

nrow(my.mat)很大,但是myFun()的计算速度很快。请注意,cl的核心数为5。我想知道如何进行并行化。

  

my.mat是否被分为5个子矩阵,然后每个子矩阵都由一个线程处理,然后在所有线程完成后合并在一起?还是通过将my.mat的元素一一发送到每个线程来完成?

1 个答案:

答案 0 :(得分:1)

以下是R文档中的一些解释:

  

parLapply parSapply parApply 是lapply的并行版本,   申请并申请。 大块计算静态分配给   使用 clusterApply 的节点。默认情况下,块数相同   作为节点数。 parLapplyLB parSapplyLB   版本,旨在将FUN应用于以下内容的不同元素时使用   X需要花费相当多的时间,并且其中一个函数是   不需要确定性或可重复的结果。的块   使用 clusterApplyLB 将计算动态分配给节点。

请注意,R / 3.5.0中进行了一些更改:

  

从R 3.5.0起,默认的块数是块数的两倍   节点。在R 3.5.0之前,块的(固定)数目与   节点数。至于 clusterApplyLB ,通过负载均衡   执行特定作业的节点是不确定的,并且   将RNG流分配给节点的模拟将无法重现。

     

clusterApply 在第一个节点上使用参数x [[1]]和   ...,在第二个节点上使用x [[2]]和...,依此类推,回收   节点。

clauterApplyLB的工作方式略有不同:

  

clusterApplyLB 是clusterApply的负载平衡版本。如果   x的长度n不大于节点p的数量,则作业为   发送到n个节点。否则,将前p个作业按顺序放置在   p个节点。当第一个作业完成时,下一个作业将放置在   已变为免费的节点;这一直持续到所有作业完成为止。   使用 clusterApplyLB 可以比   使用 clusterApply ,但是增加交流可以减少   性能。此外,执行特定作业的节点是   不确定的。这意味着分配RNG流的模拟   节点是不可复制的。

因此,当您使用parApply时,您的矩阵分为5个块。每个块均由内核之一处理。对于par * ApplyLB系列函数,将元素一一分配给内核,一旦一个内核完成其任务,便将另一个分配给它。

这是以下代码的输出:

library(parallel)


my.mat <- matrix(c(1:20,rep(0,20)), ncol=2)
head(my.mat)
#      [,1] [,2]
# [1,]    1    0
# [2,]    2    0
# [3,]    3    0
# [4,]    4    0
# [5,]    5    0
# [6,]    6    0

cl <- makeCluster(5, "FORK")
parApply(cl = cl, X = my.mat, MARGIN = 1, FUN = function(x){print(paste("sum= ", sum(x), "  pid=",Sys.getpid()))})
# [1] "sum=  1   pid= 42569" 
# [2] "sum=  2   pid= 42569" 
# [3] "sum=  3   pid= 42569" 
# [4] "sum=  4   pid= 42569" 
# [5] "sum=  5   pid= 42570" 
# [6] "sum=  6   pid= 42570" 
# [7] "sum=  7   pid= 42570" 
# [8] "sum=  8   pid= 42570" 
# [9] "sum=  9   pid= 42571" 
# [10] "sum=  10   pid= 42571"
# [11] "sum=  11   pid= 42571"
# [12] "sum=  12   pid= 42571"
# [13] "sum=  13   pid= 42572"
# [14] "sum=  14   pid= 42572"
# [15] "sum=  15   pid= 42572"
# [16] "sum=  16   pid= 42572"
# [17] "sum=  17   pid= 42573"
# [18] "sum=  18   pid= 42573"
# [19] "sum=  19   pid= 42573"
# [20] "sum=  20   pid= 42573"


stopCluster(cl)

如果我将parLapplyLB与块大小= 1一起使用,请注意以下输出的区别(请参阅pid值的分布方式):

mylist <- 1:20
cl <- makeCluster(5, "FORK")
parLapplyLB(cl = cl, X = mylist,function(x){print(paste("sum= ", sum(x), "  pid=",Sys.getpid()))}, chunk.size = 1)
# [[1]]
# [1] "sum=  1   pid= 64019"
# 
# [[2]]
# [1] "sum=  2   pid= 64020"
# 
# [[3]]
# [1] "sum=  3   pid= 64021"
# 
# [[4]]
# [1] "sum=  4   pid= 64022"
# 
# [[5]]
# [1] "sum=  5   pid= 64023"
# 
# [[6]]
# [1] "sum=  6   pid= 64019"
# 
# [[7]]
# [1] "sum=  7   pid= 64020"
# 
# [[8]]
# [1] "sum=  8   pid= 64019"
# 
# [[9]]
# [1] "sum=  9   pid= 64020"
# 
# [[10]]
# [1] "sum=  10   pid= 64019"
# . . .
stopCluster(cl)