10

我第一次在 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 
4

1 回答 1

8

for将运行sqrtB 次,大概每次都会丢弃答案。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可以看到有很多事情发生了!我还没有试图确切地理解它是如何工作的,但是do.Rforeach.R表明即使在%do%运行时,大部分foreach配置仍然在运行,如果可能在%do%很大程度上提供了该选项以允许您测试foreach代码而不必配置并加载了并行后端。它还需要支持提供的更高级的嵌套和迭代工具foreach

代码中有对结果缓存、错误检查、调试和为每次迭代的参数创建本地环境变量的引用(参见示例doSEQ中的函数do.R)。我想这就是造成您观察到的差异的原因。当然,如果您在循环中运行更复杂的代码(这实际上会受益于类似的并行化框架foreach),那么与它提供的好处相比,这种开销将变得无关紧要。

于 2012-05-02T12:59:48.567 回答