理解R中mclapply和parLapply之间的差异

时间:2013-06-19 16:16:37

标签: r parallel-processing mclapply

我最近开始在R中为项目使用并行技术,并使用mclapply包中的parallel使我的程序在Linux系统上运行。但是,我已经了解了parLapply for Windows。

使用mclapply我可以设置核心数,迭代次数,并将其传递给我工作区中的现有函数。

mclapply(1:8, function(z) adder(z, 100), mc.cores=4)

我似乎无法在使用parLapply的Windows中实现相同功能。据我了解,我需要通过使用clusterExport()传递所有变量,并将我想要应用的实际函数传递给参数。

这是正确的还是类似于适用于Windows的mclapply函数?

2 个答案:

答案 0 :(得分:27)

mclapply的美妙之处在于,工作进程都是在调用mclapply的时候创建为主人的克隆,因此您不必担心再现环境每个集群工作者。不幸的是,这在Windows上是不可能的。

使用parLapply时,通常需要执行以下附加步骤:

  • 创建PSOCK群集
  • 根据需要注册群集
  • 在群集工作者上加载必要的包
  • 将必要的数据和功能导出到集群工作者的全局环境

此外,当您完成后,最好使用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))

请注意,NULLclusterExportclusterEval的{​​{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创建集群的其他方法,并查看哪种方法最适合您的要求。