R语言并行运算(snow包)

来源:互联网 发布:js全局数组变量 编辑:程序博客网 时间:2024/06/03 20:24

snow包

snow包主要运行于传统的集群计算。它主要用于蒙特卡洛模拟(Monte Carlo simulations),boostrapping,交叉验证(cross validation),集成机器学习算法(ensemble machine learning algorithms)和K均值聚类(K-Means clustering)等,并且也很好支持并行随机数的生成。 
snow包的安装一般应用install.packages('snow')
要使用snow包进行并行运算,首先要创建一个集群对象,主要用于与内核的交互,一般传递与snow包中函数的第一个参数。 
基本的集群创建函数为makeCluster(),它能创建任何类型的集群,例如,在本地机器上创建一个4核的集群:

cl <- makeCluster(4, type="SOCK")
  • 1

第一个参数为集群设定,即设定使用的CPU数;第二个参数是集群类型。 
注意:在结束集群时使用stopCluster()。 
下面使用snow包做一个并行运算。

并行运算K均值聚类

数据是MASS包自带的Boston数据集。 
K均值函数使用stats包中的kmeans()

library(MASS)result <- kmeans(Boston, 4, nstart = 100)
  • 1
  • 2

在使用并行计算前,首先看看使用lapply函数的运行情况

results <- lapply(rep(25,4), function(nstart) kmeans(Boston, 4, nstart = nstart)i <- sapply(results, function(result) result$tot.withiness)result <- results[[which.min(i)]]
  • 1
  • 2
  • 3

使用clusterApply并行计算

library(snow)cl <- makeCluster(4, type="SOCK")ignore <- clusterEvalQ(cl, {library(MASS); NULL}) #用clusterEvalQ函数初始化内核,在每一个内核中载入包results <- clusterApply(cl, rep(25, 4), function(nstart) kmeans(Boston, 4, nstart=nstart)) #parallel computingi <- sapply(results, function(result) result$tot.withinss)result <- results[[which.min(i)]]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

相比较clusterEvalQ而言,clusterCall更好用,它的第一个参数为集群对象,第二个参数为一个函数,并且其他的参数可以传递给这个函数。最终返回一个列表。

clusterCall(cl, function() { library(MASS); NULL })
  • 1

clusterCall函数可以调用多个包,

worker.init <- function(packages) {for (p in packages) {library(p, character.only=TRUE)}NULL}clusterCall(cl, worker.init, c('MASS', 'boot'))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

character.only=TRUE是使library把参数解释为字符向量,否则library会重复载入名称为p的包。

使用clusterApplyLB并行运算

clusterApplyLBclusterApply函数相似,但clusterApplyLB的运行效率更高。在使用clusterApply并行运算时,如果每一个内核花费不同的时间进行运算,那么在那个运行时间长的内核结束之前,运行时间短的内核不能进行下一次运算,而clusterApplyLB不同,它是在运行时间短的内核结束之后接着就运行下一次的运算,这样就减少了时间的浪费,因此提高了效率。 
为了说明clusterApplyLB的效率,我们使用控制任务时间长度的函数Sys.sleep。用snow.time收集整个执行过程的时间信息。

set.seed(7777442)sleeptime <- abs(rnorm(10, 10, 10))tm <- snow.time(clusterApplyLB(cl, sleeptime, Sys.sleep))plot(tm)
  • 1
  • 2
  • 3
  • 4

clusterApplyLB 
作为对照,我们用clusterApply函数来观察运行时间

tm1 <- snow.time(clusterApply(cl, sleeptime, Sys.sleep))plot(tm1)
  • 1
  • 2

clusterApply 
由此看出clusterApplyLB效率更高。

使用parLapply并行运算

parLapply是snow包中的一个高级函数,它比clusterApply函数更高效,如果参数x的长度与内核的数量相等,parLapply的优势不明显,如果参数x的长度远大于内核的数量,parLapply相比于clusterApply是一个更好的选择。 
应用一个并行休眠函数的用法,首先使用clusterApply

bigsleep <- function(sleeptime, mat) Sys.sleep(sleeptime)bigmatrix <- matrix(0, 2000, 2000)sleeptime <- rep(1, 100)tm2 <- snow.time(clusterApply(cl, sleeptime, bigsleep, bigmatrix))plot(tm2)
  • 1
  • 2
  • 3
  • 4
  • 5

clusterApply 
由图看出并不高效,因为有大量的输入输出时间,下面再试一试clusterApplyLB

tm3 <- snow.time(clusterApplyLB(cl, sleeptime, bigsleep, bigmatrix))plot(tm3)
  • 1
  • 2

clusterApplyLB 
由上图看出,运算集中在第1、2和3个内核上,第4个内核上运算的时间非常少,及运算效率差,但总体还是比clusterApply函数要好一些。 
看看最终的函数parLapply

tm4 <- snow.time(parLapply(cl, sleeptime, bigsleep, bigmatrix))plot(tm4)
  • 1
  • 2

parLapply 
由此看出,传输交换的时间大大缩短了,因此提高了效率。

原创粉丝点击