使用parallel包实现R语言并行
R语言{parallel}包里的apply族函数可以实现R层面的粗粒度并行,结合clusterEvalQ和clusterExport让复杂的并行用最简单的语句实现。
# 什么是并行?
在上手R语言并行之前,我们首先需要了解一下什么是并行。 并行是指计算机将工作各部分分配到不同处理进程(线程)。 并行的概念与串行相对,他们的关系类似于初中电路里的并联和串联。电流经过电路会产生电能消耗,同理工作流经过processing也会产生对应的计算资源消耗或者系统开销; 串联电路间的短路会导致电路故障,同理并行处理间如果存在相互关联则无法正确运行。 此外,并行也不能保证加速,但从理论上讲,在 n 个并行处理的执行速度可能会是在单一处理机上执行的速度的 n 倍。 并行有很多层次,parallel这个包实现的是最上层的Rscript层面的并行,即开启多个Rsession执行并行程序
# 并行的准备
既然parallel的原理实际上就是多个Rsession,那么必然需要指定node的数量并为每个node给出需要的环境变量。
library(parallel)
cl = makeCluster(4) # 并行的session数量,此处为4
varlist = c("x","y")
clusterExport(cl, varlist) # varlist即需要赋给每个独立node的变量,形式为字符串。
expr = {library(R2OpenBUGS)}
clusterEvalQ(cl, expr) # expr即每个session运行前所要执行的语句
2
3
4
5
6
# 并行函数
parallel包的并行函数有很多,只介绍apply族函数。apply族函数的特点就是参数中的“...”,即直接通过添加对应参数来为fun指定默认参数。很关键因为很方便。
clusterApply(cl, x, fun, ...)
clusterApply
函数可以对一个向量x(单元素列表也是可以的)的每一个元素进行并行处理,本人常用于x本身没啥意义的情形。返回列表。
clusterMap(cl = NULL, fun, ..., MoreArgs = NULL, RECYCLE = TRUE,SIMPLIFY = FALSE, USE.NAMES = TRUE,.scheduling = c(static, dynamic))
clusterApply升级版,对应mapply。与后者相似,可以指定多组变量。所有变量长度必须相等,在machine learning调参的时候比较好用,可以直接指定变量的组合形式。.scheduling参数用于指定local balancing(dynamic)。
parLapply(cl = NULL, X, fun, ..., chunk.size = NULL)
parSapply(cl = NULL, X, FUN, ..., simplify = TRUE, USE.NAMES = TRUE, chunk.size = NULL)
2
对应lapply
和sapply
。与clusterApply
的区别在于X可以是更复杂的列表(比如list中套list)。前者只能返回列表,后者通过simplify调整返回形式为array。
parApply(cl = NULL, X, MARGIN, FUN, ..., chunk.size = NULL)
parRapply(cl = NULL, x, FUN, ..., chunk.size = NULL)
parCapply(cl = NULL, x, FUN, ..., chunk.size = NULL)
2
3
对应apply
。用于对矩阵进行并行处理。parRapply
相当于默认MARGIN=1,对每行执行;parCapply
相当于默认MARGIN=2,对每列执行。parApply
的返回结果与apply一样,parRapply
和parCapply
返回向量。
# 局部均衡 (LB)
在默认情况下,R语言会在事先依次序安排每个节点执行的任务,即所谓的statis chedule,但是这样做的话单次任务需要的时间差不多还好,要是少数任务特别耗时间就会拖累整体速度。为了避免这种情况的发生,可以使用动态的计划方法实现本地负载均衡,即dynamic schedule。与statis chedule不同,dynamic schedule不会事先安排单个节点所有的对应任务,而是根据节点是否完成上次任务之后,再行安排任务。这样的动态计划也存在缺陷,由于主进程需要频繁地与节点进行通信,可能会使得平均速度降低。 **parLapplyLB/parSapplyLB/clusterApplyLB
分别是parLapply/parSapply/clusterApply
**的LB版本,clusterMap
可以通过指定.scheduling
参数为dynamic实现local balancing。
# 简单案例
前两天简单写了一个并行,放在这里供大家看看。
combination=combn(setdiff(species,exception),2,simplify=FALSE)
cl = makeCluster(multicore)
clusterEvalQ(cl,{library(R2OpenBUGS);library(ape);library(DMwR)})
clusterExport(cl, c("data","find_col","species","unimodal_modelling","bimodal_modelling", "wd","extract_object_clade_phy","unimodal_file","bimodal_file", "species_tree","lof_threshold"))
parLapply(cl,combination,function(x){ nam=paste(x,collapse='_')
d=data[,find_col(species,x[1],x[2])]
names(d)=rownames(data)
m1=unimodal_modelling(d,nam,wd,unimodal_file) })
stopCluster(cl)
2
3
4
5
6
7
8
9
题外话 云顶2.0出来了,炉石自走棋也开放了,感觉睡眠时间减少了好多啊。