5

我在获取一些代码以使用 R 中的并行包时遇到问题。我使用的是 R 2.15。

这是一个简化的示例...我有一个文件“animal.R”,其中包含以下内容:

# animal.R
setClass("Animal", representation(species = "character", legs = "numeric"))

##Define some Animal methods
setGeneric("count",function(x) standardGeneric("count"))
setMethod("count", "Animal", function(x) { x@legs})

setGeneric("countAfterChopping",function(x) standardGeneric("countAfterChopping"))
setMethod("countAfterChopping", "Animal", function(x) { x@legs <- x@legs-1; x@legs})

然后,在我的 R 终端中,我运行:

library(parallel)
source('animal.R')

启动两个节点的本地集群:

cl <- makeCluster(rep('localhost', 2))

告诉集群节点有关 Animal 类的信息:

clusterEvalQ(cl, parse('animal.R'))

然后在集群上运行一些代码:

# This works
parSapply(cl, list(daisy, fred), count)

# This doesn't...
parSapply(cl, list(daisy, fred), countAfterChopping)

停止集群:

stopCluster(cl)

对 parSapply 的第一次调用按预期工作,但第二次产生此错误:

Error in checkForRemoteErrors(val) : 
  2 nodes produced errors; first error: "Animal" is not a defined class

有什么想法吗?为什么第二次调用 parSapply 不起作用?

4

1 回答 1

3

所以这就是发生的事情:

对于“Animal”类的 S4 对象,该count函数只是提取legs槽。如果这就是您所做的一切,您就不需要评估或获取animal.R集群节点上的文件。所有必要的信息都将通过parSapply

但是,该countAfterChopping函数为插槽分配了一个新值legs,这就是有趣的开始。插槽分配函数`@<-`包含`slot<-`对参数的调用check = TRUE。这会触发对函数的评估,该函数checkSlotAssignment通过查询类的定义来检查“提供的值是否允许用于该插槽”(来自?checkSlotAssignment)。

因此,以这种方式分配到槽时必须知道类定义,并且在集群节点上不知道S4类“Animal”。这就是为什么评估解析的文件animal.R或获取它的工作原理。但是,您可以只评估文件的第一行,即在每个节点上定义类“Animal”。

这是一个简化的、可重现的示例:

animal.R<-"
  setClass('Animal', representation(species = 'character', legs = 'numeric'))

  ##Define some Animal methods
  setGeneric('count',function(x) standardGeneric('count'))
  setMethod('count', signature(x='Animal'), function(x) { x@legs})

  setGeneric('countAfterChopping',function(x) standardGeneric('countAfterChopping'))
  setMethod('countAfterChopping', signature(x='Animal'),
    function(x) { x@legs <- x@legs-1; x@legs})
"
library(parallel)

source(textConnection(animal.R))

cl <- makeCluster(rep('localhost', 2))

daisy<-new("Animal",legs=2,species="H.sapiens")
fred<-new("Animal",legs=4,species="C.lupus")

parSapply(cl, list(daisy, fred), count)
# [1] 2 4

clusterExport(cl,"animal.R") # 
clusterEvalQ(cl,eval(parse(textConnection(animal.R),n=1)))

parSapply(cl, list(daisy, fred), countAfterChopping)
# [1] 1 3
于 2012-05-25T06:22:07.443 回答