上一篇博客(R中两种常用并行方法之parallel)中已经介绍了R中常见的一种并行包:parallel
,其有着简单便捷等优势,其实缺点也是非常明显,就是很不稳定。很多时候我们将大量的计算任务挂到服务器上进行运行时,更看重的是其稳定性。
这时就要介绍R中的另一个并行利器——snowfall
,这也是在平时做模拟时用的最多的一种方法。
针对上篇中的简单例子
首先是一个最简单的并行的例子,这个例子不需要载入任何依赖库、函数、对象等。相对也比较简单:
library(snowfall) # 载入snowfall包 # 并行初始化 sfInit(parallel = TRUE, cpus = detectCores() - 1) # 进行lapply的并行操作 sfLapply(1:3, function(x) c(x, x ^ 2, x ^ 3)) # 结束并行,返还内存等资源 sfStop()
语法基本也比较好理解,代码中的注释也有进行说明。sfLapply()
的操作是与lapply()
相对应的。类似地,还有sfSapply()
,sfApply()
等函数,其用法与apply
组中的函数一致。
snowfall进阶
在实际操作时,我们进行的函数往往没有这么简单,往往还需要依赖一些其它的函数、变量、R包等,这时就不能用上述的方法简单的进行操作了。
下面给出一个具体实际的操作案例,来展示如何载入函数中依赖的对象等参数。
n <- 100 m <- 100 fun1 <- function(...) { ... } fun2 <- function(...) { ... } sfInit(parallel = TRUE, cpus = 10) #初始化 sfLibrary(MASS) # 载入依赖R包MASS sfLibrary(ggplot2) # 载入依赖R包ggplot2 sfExport("n", "m") # 载入依赖的对象 sfExport("fun1", "fun2") # 载入依赖的函数 # 并行计算 result <- sfLapply(1:10000, myfun) # 注意:myfun是自己定义的函数,里面需要用到包MASS, ggplot2;变量m, n;函数fun1, fun2。 sfStop() # 结束并行
其实很简单,对于并行函数依赖的库,就是sfLibrary()
进行载入,所以来的对象以及函数则使用sfExport()
进行载入。
当函数或者对象非常多时,不方便一个一个单独输入,这时我们可将所有的对象与函数存到allfun.R
文件夹中,然后再采用sfSource('allfun.R')
将所有的对象与函数进行导入,方便快捷。
下面我们再来看看如何查看并行进度:
使用sfCat查看并行进度
这部分参考:How to output a message in snowfall?
我们只需在函数中添加sfCat()
函数,即可查看并行进度,其示例代码如下所示:
sfInit(parallel = TRUE, cpus = 2, slaveOutfile = "test.txt") sfLibrary(snowfall) res <- sfLapply(1:100, function(x) { sfCat(paste("Iteration ", x), sep = "\n") }) sfStop()
需要注意的是,在初始化并行中,我们多加了一串命令:slaveOutfile = "test.txt"
,这个表示其显示的进度会储存在test.txt
文件中,其余部分基本没什么变化。
与Rcpp结合会遇到的问题
当我们进行模拟想要再次进行提速时,通常都会使用Rcpp将我们的R代码改成C++代码。平时在我们使用的时候,直接使用Rcpp::sourceCpp()
就可以直接将我们的C++代码中的函数进行导入,然想要使用snowfall
进行并行时则会遇到问题。
这里使用了两种方法来进行尝试:
使用sfSource('myCppfun.cpp')
进行导入,会在导入的时候直接报错。
先使用Rcpp::sourceCpp('myCppfun.cpp')
将函数读入变量空间,然后再使用sfExport("myCppfun")
将函数。这样做在最后运行代码的时候会报错。
所以遇到这种问题,只能将我们的C++代码中的函数打包成一个包,然后直接在使用snowfall
进行并行时,调取这个包来运行则不会报错。
关于如何制作自己的R包,可参考:RStudio制作包含Rcpp代码的R包。
以上就是R语言常用两种并行方法之snowfall详解的详细内容,更多关于R语言并行snowfall方法的资料请关注其它相关文章!