我do.call
在并行化环境中嵌套了多个级别(每个级别本身都使用参数中命名的函数,而不是硬编码)%dopar%
,并且最里面的函数无法找到来自外部环境的函数。我知道.export
参数 onforeach
并正在使用它,但不知何故,命名函数并没有沿着整个链传播。
我将问题简化为以下测试用例,它确实存在此问题:
library(doParallel)
cl <- makeCluster(4)
registerDoParallel(cl)
simple.func <- function(a, b) {
return(a+b)
}
inner.func <- function(a, b) {
return(do.call(simple.func, list(a=a, b=b)))
}
outer.func <- function(a, b, my.func=inner.func) {
return(do.call(my.func, list(a=a, b=b)))
}
main.func <- function(my.list=1:10, my.func=outer.func,
my.args=list(my.func=inner.func)) {
results <- foreach(i=my.list, .multicombine=TRUE, .inorder=FALSE,
.export="simple.func") %dopar% {
return(do.call(my.func, c(list(a=i, b=i+1), my.args)))
}
return(results)
}
我没有给出正确答案(带有一些数字的列表),而是得到:
Error in { : task 1 failed - "object 'simple.func' not found"
添加if (!exists("simple.func")) stop("Could not find parse.data in scope main.func")
到每个函数的开头(根据需要更改范围的名称)表明它是inner.func
看不到的simple.func
——即使outer.func
确实看到了。
我还测试了上面的几个变体,或者main.func
硬outer.func
编码下一级函数,而不是从参数中使用它。这两种变体都有效(例如,给出预期的结果),但对于现实世界的情况,我想保留将子函数作为参数的普遍性。
# Variation number one: Replace main.func() with this version
main.func <- function(my.list=1:10, my.func=outer.func,
my.args=list(my.func=inner.func)) {
results <- foreach(i=my.list, .multicombine=TRUE, .inorder=FALSE,
.export=c("simple.func", "outer.func", "inner.func")) %dopar% {
return(do.call(outer.func, list(a=i, b=i+1, my.func=inner.func)))
}
return(results)
}
# Variation number two: Replace outer.func() and main.func() with these versions
outer.func <- function(a, b, my.func=inner.func) {
return(do.call(inner.func, list(a=a, b=b)))
}
main.func <- function(my.list=1:10, my.func=outer.func,
my.args=list(my.func=inner.func)) {
results <- foreach(i=my.list, .multicombine=TRUE, .inorder=FALSE,
.export=c("simple.func", "inner.func")) %dopar% {
return(do.call(my.func, c(list(a=i, b=i+1), my.args)))
}
return(results)
}
我也可以simple.func
手动传递链,将它作为一个额外的参数包含在内,但这看起来非常混乱,为什么在simple.func
应该作为环境的一部分传递时有必要呢?
# Variation number three: Replace inner.func(), outer.func(), and main.func()
# with these versions
inner.func <- function(a, b, innermost.func=simple.func) {
return(do.call(innermost.func, list(a=a, b=b)))
}
outer.func <- function(a, b, my.func=inner.func,
innermost.args=list(innermost.func=simple.func)) {
return(do.call(my.func, c(list(a=a, b=b), innermost.args)))
}
main.func <- function(my.list=1:10, my.func=outer.func,
my.args=list(my.func=inner.func,
innermost.args=list(innermost.func=simple.func))) {
results <- foreach(i=my.list, .multicombine=TRUE, .inorder=FALSE,
.export="simple.func") %dopar% {
return(do.call(my.func, c(list(a=i, b=i+1), my.args)))
}
return(results)
}
有没有人有关于不那么笨拙的解决方案的想法,或者这个问题的根本原因?