我可以同时使用for循环和apply族的并行版本吗?
最近我在做研究时遇到了一个问题:首先,我定义了一个函数我可以同时使用for循环和apply族的并行版本吗?,r,for-loop,parallel-processing,apply,doparallel,R,For Loop,Parallel Processing,Apply,Doparallel,最近我在做研究时遇到了一个问题:首先,我定义了一个函数myfunction,其中包含两个for循环,然后我使用lappy(datalist,myfunction),但处理速度太慢 然后我学习了两个并行包“foreach”和“parallel”来进行并行计算。因此,我将这两个进程都更改为并行版本 但我发现,当我运行代码时,函数中的foreach似乎不起作用 myfunction <- function{data} { df <- foreach (i = 1:200, .co
myfunction
,其中包含两个for循环,然后我使用lappy(datalist,myfunction)
,但处理速度太慢
然后我学习了两个并行包“foreach”和“parallel”来进行并行计算。因此,我将这两个进程都更改为并行版本
但我发现,当我运行代码时,函数中的foreach似乎不起作用
myfunction <- function{data} {
df <- foreach (i = 1:200, .combine = "rbind") %:%
foreach(j = 1:200, .combine = "rbind") %dopar% {
*****
process
*****
}
data <- df[1,1]
return(data)
}
system.time({
cl <- detectCores()
cl <- makeCluster(cl)
registerDoParallel(cl)
mat <- t(parSapply(cl, list, myfuntion))
stopCluster(cl)
})
myfunction
我觉得这是因为parSapply占据了整个核心,所以foreach没有额外的核心来计算。有什么好办法来修理它吗?基本上,我想实现两个进程在并行版本中运行
不,这不是个好主意。在这里,您基本上是在尝试过度并行化(但正如下面所解释的,这确实发生在您的代码中)
另一个问题是:假设我们只能选择一个进程来进行并行计算,我应该选择哪一个?for循环还是apply族
没有一个正确的答案。我建议您分析您的***进程***
代码,以了解它从并行化中获得了多少收益
因此,我发现您的parSapply(cl,…)
位于foreach()%dopar%{…}
顶部,使用相同的集群cl
很有趣。我第一次看到这样的提问/提议。你肯定不想这么做,但这个问题/尝试并不疯狂。您的直觉是,当foreach()%dopar%{…}
尝试使用它们时,所有工作人员都会被占用,这在一定程度上是正确的。然而,真正发生的事情是,foreach()%dopar%{…}
语句在workers中进行计算,而不是在定义集群cl
的主R会话中进行计算。在worker上,没有注册foreach适配器,因此这些调用将默认为顺序处理(=foreach::registerDoSEQ()
)。为了实现嵌套并行化,您必须在每个worker内设置并注册一个集群,例如在myfunction()
函数内
作为该框架的作者,我想建议您利用它。它将保护您免受上述错误的影响,而且也不会过度并行(如果您真的想这样做,您可以这样做)。下面是我将如何重写您的代码示例:
library(foreach) ## foreach() and %dopar%
myfunction <- function{data} {
df <- foreach(i = 1:200, .combine = "rbind") %:%
foreach(j = 1:200, .combine = "rbind") %dopar% {
*****
process
*****
}
data <- df[1,1]
return(data)
}
## Tell foreach to parallelize via the future framework
doFuture::registerDoFuture()
## Have the future framework parallelize using a cluster of
## local workers (similar to makeCluster(detectCores()))
library(future)
plan(multisession)
library(future.apply) ## future_sapply()
system.time({
mat <- t(future_sapply(list, myfuntion))
})
如果确实要进行嵌套并行化,例如,两个外部级别的辅助对象和4个内部级别的辅助对象,可以使用:
plan(list(tweak(multisession, workers = 2), tweak(multisession, workers = 4))
这将同时运行2*4=8个并行R进程
更有用的是,当您有多台机器可用时,您可以将这些机器用于外部级别,然后在每个机器上使用多会话集群。比如:
plan(list(tweak(cluster, workers = c("machine1", "machine2")), multisession))
您可以在vignettes中了解更多信息。您所说的“不起作用”是什么意思?@JérômeRichard当列表
仅包含一个数据集时,我运行相同的代码。理想情况下,我希望调用所有的内核进行计算,但这表明只使用了大约10-15%的cpu。换句话说,我的denied函数中的foreach
不起作用。我想我会尝试您在稍后的回复中提到的嵌套并行化。顺便说一句,组合多台机器的代码非常好。谢谢:D
plan(list(tweak(cluster, workers = c("machine1", "machine2")), multisession))