我第一次在R中进行并行化。作为第一个玩具示例,我试过
library(doMC)
registerDoMC()
B<-10000
myFunc<-function()
{
for(i in 1:B) sqrt(i)
}
myFunc2<-function()
{
foreach(i = 1:B) %do% sqrt(i)
}
myParFunc<-function()
{
foreach(i = 1:B) %dopar% sqrt(i)
}
我知道sqrt()
执行速度太快,无法实现并行化,但我没想到的是foreach() %do%
会慢于for()
:
> system.time(myFunc())
user system elapsed
0.004 0.000 0.005
> system.time(myFunc2())
user system elapsed
6.756 0.000 6.759
> system.time(myParFunc())
user system elapsed
6.140 0.524 6.096
在我看过的大多数示例中,foreach() %dopar%
与foreach() %do%
而非for()
进行比较。由于foreach() %do%
在我的玩具示例中比for()
慢得多,我现在有点困惑。不知何故,我认为这些是构造for循环的等效方法。有什么不同?它们是否相同? foreach() %do%
总是慢一点吗?
更新:关注@Peter Fines回答,我更新myFunc
如下:
a<-rep(NA,B)
myFunc<-function()
{
for(i in 1:B) a[i]<-sqrt(i)
}
这会使for()
慢一点,但不会太多:
> system.time(myFunc())
user system elapsed
0.036 0.000 0.035
> system.time(myFunc2())
user system elapsed
6.380 0.000 6.385
答案 0 :(得分:8)
for
将运行sqrt
次B次,可能每次丢弃答案。但是,foreach
返回一个列表,其中包含循环体每次执行的结果。无论是以并行模式还是顺序模式(%dopar%
或%do%
)运行,这都会带来相当大的额外开销。
我通过运行以下代码来建立我的答案,该代码似乎由foreach vignette确认,其中指出“foreach与for循环的不同之处在于它的返回值是值列表,而for循环有没有价值,并使用副作用来传达其结果。“
> print(for(i in 1:10) sqrt(i))
NULL
> print(foreach(i = 1:10) %do% sqrt(i))
[[1]]
[1] 1
[[2]]
[1] 1.414214
[[3]]
... etc
更新:我从您更新的问题中看到,上述答案几乎不足以说明性能差异。所以我查看foreach
的{{3}},可以看到有很多事情发生了!我没有试图准确理解它是如何工作的,但do.R
和foreach.R
表明即使运行%do%
,foreach
配置的大部分仍在运行,如果可能提供%do%
选项以允许您测试foreach
代码而无需配置和加载并行后端,那么这将是有意义的。它还需要支持foreach
提供的更高级的嵌套和迭代功能。
代码中有一些引用用于结果缓存,错误检查,调试以及为每次迭代的参数创建局部环境变量(例如,参见doSEQ
中的函数do.R
)。我想这就是你所观察到的差异。当然,如果你在循环中运行更复杂的代码(实际上会从像foreach
这样的并行化框架中受益),与它提供的好处相比,这种开销将变得无关紧要。