我最近开始在R中为项目使用并行技术,并使用mclapply包中的parallel使我的程序在Linux系统上运行。但是,我已经了解了parLapply
for Windows。
使用mclapply
我可以设置核心数,迭代次数,并将其传递给我工作区中的现有函数。
mclapply(1:8, function(z) adder(z, 100), mc.cores=4)
我似乎无法在使用parLapply
的Windows中实现相同功能。据我了解,我需要通过使用clusterExport()
传递所有变量,并将我想要应用的实际函数传递给参数。
这是正确的还是类似于适用于Windows的mclapply
函数?
答案 0 :(得分:27)
mclapply
的美妙之处在于,工作进程都是在调用mclapply
的时候创建为主人的克隆,因此您不必担心再现环境每个集群工作者。不幸的是,这在Windows上是不可能的。
使用parLapply
时,通常需要执行以下附加步骤:
此外,当您完成后,最好使用stopCluster
关闭PSOCK群集。
以下是您的示例到parLapply
的翻译:
library(parallel)
cl <- makePSOCKcluster(4)
setDefaultCluster(cl)
adder <- function(a, b) a + b
clusterExport(NULL, c('adder'))
parLapply(NULL, 1:8, function(z) adder(z, 100))
如果您的adder
函数需要一个包,那么在使用parLapply
调用它之前,您必须在每个worker上加载该包。您可以使用clusterEvalQ
轻松完成此操作:
clusterEvalQ(NULL, library(MASS))
请注意,NULL
,clusterExport
和clusterEval
的{{1}}第一个参数表示他们应该使用通过parLapply
注册的群集对象。如果您的程序在许多不同的函数中使用setDefaultCluster
,那么这非常有用,这样您在转换程序以使用mclapply
时就不必将集群对象传递给需要它的每个函数。
当然,parLapply
可能会调用全局环境中调用其他函数等的其他函数。在这种情况下,您还必须导出它们并加载它们所需的任何包。另请注意,如果您导出的任何变量在程序过程中发生更改,则必须再次导出它们才能在群集工作器上更新它们。同样,adder
不需要这样做,因为无论何时调用它,它总是创建/克隆/分叉工作,这使得它不必要。
答案 1 :(得分:3)
mclapply使用起来更简单,并使用底层操作系统fork()功能来实现并行化。但是,由于Windows没有fork(),因此它将运行标准lapply而不是并行化。
parLapply是一个不同的野兽。它将创建一个进程集群,甚至可以驻留在网络上的不同机器上,并通过TCP / IP进行通信,以便在彼此之间传递任务和结果。
您的代码中存在的问题是您没有意识到parLapply的第一个参数应该是“群集”对象。使用parLapply在我能想到的单个机器上运行的最简单的例子是:
library(parallel)
# Spawn child processes using fork() on the local machine
cl <- makeForkCluster(getOption("cl.cores", 2))
# Use parLapply to calculate lengths of 1000 strings
text = rep("Hello, world!", 1000)
len = parLapply(cl, text, nchar)
# Kill child processes since they are no longer needed
stopCluster(cl)
如上所述,使用parFapply与使用makeForkCluster创建的集群在功能上等同于调用mclapply。所以它也无法在Windows上运行。 :)看看在文档中使用makeCluster和makePSOCKcluster创建集群的其他方法,并查看哪种方法最适合您的要求。