我已经成功地并行了一个函数 - 让我们通过doParallel
软件包,foreach
和%dopar%
称其为AddOne
-我熟悉.packages
和.export
参数到foreach
。
我的问题是,我希望AddOne
,而不是成为"独立"功能,成为列表的要素,在这种情况下,我无法使事情有效。具体来说,如果AddOne
调用子例程AddOneSubroutine
,则AddOneSubroutine
在"工作"环境中也找不到,即使它被"导出"。
我正在使用Windows 10,而R.version
产量:
platform x86_64-w64-mingw32
arch x86_64
os mingw32
system x86_64, mingw32
status
major 3
minor 4.1
year 2017
month 06
day 30
svn rev 72865
language R
version.string R version 3.4.1 (2017-06-30)
nickname Single Candle
我拥有的多巴平行版本是1.0.10。这是一些代码,可以尽我所能。
library(doParallel)
if(!exists("Registered")){
registerDoParallel(cores = detectCores(logical = TRUE))
Registered = TRUE
}
AddOne<-function(x){AddOneSubroutine(x)}
AddOneSubroutine <-function(x){x+1}
MyList<-list()
MyList$f<-AddOne
# Not using parallel environments, works correctly when calling AddOne 3 times
Result1 = foreach(i = 1:3) %do% AddOne(i)
Result1
# Not using parallel environments, works correctly when calling MyList$f 3 times
Result2 = foreach(i = 1:3) %do% MyList$f(i)
Result2
# Using parallel environments, works correctly when calling AddOne 3 times,
# despite not explicitly using the .export argument to export AddOneSubroutine
Result3 = foreach(i = 1:3) %dopar% AddOne(i)
Result3
# Using parallel environments, fails when calling MyList$f with error
# "could not find function "AddOneSubroutine"", even though that function is "exported"
Result4 = foreach(i = 1:3,.export = "AddOneSubroutine") %dopar% MyList$f(i)
Result4
我无法理解什么?
在任何地方进行完整的可重复性,让我们确保我们在背景中使用工人:
library("doParallel")
cl <- parallel::makeCluster(detectCores(logical = TRUE))
registerDoParallel(cl)
现在,我还没有详细介绍多帕尔的后端代码,因此我不确定是什么原因导致了这个问题。但是我们知道AddOneSubroutine
确实是导出的,您可以查看是否使用foreach(..., .verbose = TRUE)
,或者简单地进行:
AddOneSubroutine <- function(x) { x + 1 }
y <- foreach(i = 1L, .export = "AddOneSubroutine") %dopar% {
get("AddOneSubroutine")
}
str(y)
## List of 1
## $ :function (x)
## ..- attr(*, "srcref")=Class 'srcref' atomic [1:8] 1 20 1 40 20 40 1 1
## .. .. ..- attr(*, "srcfile")=Classes 'srcfilecopy', 'srcfile' <environment: 0x2e475a0>
但是,当调用函数MyList$f()
时,找不到,可以通过以下方式确认:
AddOne <- function(x) exists("AddOneSubroutine")
MyList <- list()
MyList$f <- AddOne
y <- foreach(i = 1L, .export = "AddOneSubroutine") %dopar% {
MyList$f(i)
}
str(y)
## List of 1
## $ : logi FALSE
那么,为什么AddOneSubroutine
在MyList$f
中搜索的帧中不在框架中?这可能是因为多帕尔无法获得MyList$f
正确的环境。似乎有效的解决方法是以下黑客:
AddOne <- function(x) { AddOneSubroutine(x) }
y <- foreach(i = 1L) %dopar% {
environment(MyList$f) <- environment(AddOneSubroutine)
MyList$f(i)
}
str(y)
## List of 1
## $ : num 2
不幸的是,它不是很整洁,也不是很方便。
作为替代方案,Dofuture后端(我是作者)似乎效果更好:
library("doFuture")
registerDoFuture()
plan(multisession)
AddOneSubroutine <- function(x) { x + 1 }
AddOne <- function(x) { AddOneSubroutine(x) }
MyList <- list()
MyList$f <- AddOne
y <- foreach(i = 1L) %dopar% {
AddOneSubroutine ## dummy guiding auto-export
MyList$f(i)
}
str(y)
## List of 1
## $ : num 2
ps。您特别的用例让我感兴趣,因为理想情况下,AddOneSubroutine
应该在使用Dofuture时自动导出,但事实并非如此。我在基础的Globals包中找到了解决方案(我是作者),但是在发布之前,我需要对其进行更多考虑。
我的详细信息:
> sessionInfo()
R version 3.4.1 (2017-06-30)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 16.04.3 LTS
Matrix products: default
BLAS: /usr/lib/atlas-base/atlas/libblas.so.3.0
LAPACK: /usr/lib/atlas-base/atlas/liblapack.so.3.0
locale:
[1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
[3] LC_TIME=en_US.UTF-8 LC_COLLATE=en_US.UTF-8
[5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8
[7] LC_PAPER=en_US.UTF-8 LC_NAME=C
[9] LC_ADDRESS=C LC_TELEPHONE=C
[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
attached base packages:
[1] parallel stats graphics grDevices utils datasets methods
[8] base
other attached packages:
[1] doFuture_0.5.1 iterators_1.0.8 foreach_1.4.3 future_1.6.1
loaded via a namespace (and not attached):
[1] compiler_3.4.1 tools_3.4.1 listenv_0.6.0 codetools_0.2-15
[5] digest_0.6.12 globals_0.10.2