并行计算有显性并行和隐式并行,
隐式并行:OpenBLAS,Intel MKL,NVIDIA cuBLAS,H2O(参考我的博客)等
显性并行:parallel(主打lapply应用)、foreach(主打for循环)、SupR、还有利用GPU的办法(gpuR)
介绍可以参考:
https://cosx.org/2016/09/r-and-parallel-computing
parallel是比较基础的,不需要额外安装,直接加载就行,但是不是很稳定
parallel包
paralle包的并行主要靠parLapply()、parSapply()、parApply()、parRapply()、parCapply()函数实现
cl<- makeCluster(detectCores())
all.pcg <- c("httr","jsonlite","magrittr")
worker.init <- function(p) sapply(p,library,character.only=TRUE)
clusterCall(cl, worker.init, all.pcg)
#此句用于将各个子进程的环境全部加载分配到各进程环境中
mydata2 <- parLapply(
cl, #进程环境
1:16, #遍历参数
GETPDF #测试代码语句
) %>% rlist::list.rbind()
stopCluster(cl)
cl <- makePSOCKcluster(使用核的数量)
clusterExport(cl,输入变量)
clusterEvalQ(cl, 输入包)
x <- parLapply(cl,循环次数,函数)
情形1:
myfun <- function(x){
x^2
}
这个函数输入就只有x,则并行可以如下
cl <- makePSOCKcluster(2) #使用两个核
out <- parLapply(cl,1:10,myfun) # 这样1:10直接输入到函数myfun里面,作为x的值
情形2:
myfun <- function(x){
x^2 + y + z
}
这时候函数里除了x还多出来y和z,先给y和z赋值
y <- 1
z <- 2
通过clusterExport把赋值的变量送进函数里面
cl <- makePSOCKcluster(2)
clusterExport(cl,c("y","z")) #传输外部变量
out <- parLapply(cl,1:10,myfun)
情形3:
myfun <- function(x){
某函数(x^2 + y + z)
}
这个情形需要用到某函数,该函数包含在某包中。这时候需要通过clusterEvalQ将某包传入
cl <- makePSOCKcluster(2)
clusterExport(cl,c("y","z"))
clusterEvalQ(cl,c("某包"))
x <- parLapply(cl,1:10,myfun)
stopCluster(cl)
gc()
foreach包
实例
# foreach
library(foreach)
library(doParallel)
#分配核心数,这里获取了物理核心数
cores <- detectCores(logical=F)
cl <- makeCluster(cores)
registerDoParallel(cl, cores=cores)
system.time(
#.combine是数据的合并方法,如果缺省则返回一个list
res <- foreach(i=1:20, .combine='rbind', .packages=c('需要的包')) %dopar%
{
#主要代码区域
for (j in 1:100000) {
s=i+j
}
return(s)
}
)
#关闭并行
stopImplicitCluster()
stopCluster(cl)
参数介绍
%do%
: 严格按照顺序执行任务(所以,也就非并行计算),%dopar%
并行执行任务,%do%
时候就像sapply或lapply,%dopar%
就是并行启动器.combine
:运算之后结果的显示方式,default是list,“c”返回vector, cbind和rbind返回矩阵,并把数据整合起来..init
:.combine函数的第一个变量.final
:返回最后结果.inorder
:TRUE则返回和原始输入相同顺序的结果(对结果的顺序要求严格的时候),FALSE返回没有顺序的结果(可以提高运算效率)。这个参数适合于设定对结果顺序没有需求的情况。.muticombine
:设定.combine函数的传递参数,default是FALSE表示其参数是2,TRUE可以设定多个参数.maxcombine
:设定.combine的最大参数.errorhandling
:如果循环中出现错误,对错误的处理方法.packages
:指定在%dopar%运算过程中依赖的package(%do%会忽略这个选项),用于并行一些机器学习算法。.export
:在编译函数的时候需要预先加载一些内容进去,类似parallel的clusterExport
用法举例:
x <- foreach(ii=1:100,.combine = "c",.export = c("semimetric.pca","quadratic"))%dopar% func(ii)
Snowfall包
另外一个比较稳定的并行包是snowfall依赖snow包和parallel包,可以参考:
可以比较一下运行速度:
library(parallel) #用于并行计算
library(snowfall) # 载入snowfall包,用于并行计算
system.time(
for (i in 1:2250) {
for (j in 1:100000) {
s=i+j
}
}
)
myfun<-function(i){
for (j in 1:100000) {
s=i+j
}
}
system.time(
# 并行初始化
sfInit(parallel = TRUE, cpus = detectCores(logical = F) - 1)
# 进行lapply的并行操作
s<-sfLapply(1:2250, myfun)
# 结束并行,返还内存等资源
sfStop()
)
snowfall的一般框架
library((parallel))
library(snowfall)
#初始化计算群
sfInit(parallel = TRUE, cpus = min(coresmax,detectCores(logical = T)))
sfExport(XXX)#为每个进程载入相关的函数,数据
sfLibrary(XXX)#为每个进程载入相关的包
parlresult<-sfLapply(1:100, fun)
sfStop() #结束并行
并行计算的嵌套
对于第一级并行化,必须使用分布式内存技术(如 snow 包中的 makeCluster()),而在第二级并行化中,必须使用共享内存技术(多核包,mclapply())。