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%と比較されています。私のおもちゃの例よりもはるかに遅かったので、少し混乱しています。どういうわけか、これらは for ループを構築する同等の方法だと思いました。違いはなんですか?それらは同等ですか?いつも遅いですか?foreach() %do%for()foreach() %do%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

forB回実行さsqrtれ、おそらく毎回答えが破棄されます。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.Rいます。並列バックエンドを構成してロードします。また、提供されるより高度なネストおよび反復機能をサポートする必要もあります。foreach.R%do%foreach%do%foreachforeach

コードには、結果のキャッシュ、エラー チェック、デバッグ、および各反復の引数に対するローカル環境変数の作成への参照があります (例の関数doSEQを参照do.R)。これが、あなたが観察した違いを生み出すものだと思います。もちろん、ループ内ではるかに複雑なコードを実行している場合 (これは実際には のような並列化フレームワークの恩恵を受けるでしょうforeach)、このオーバーヘッドはそれが提供する利点と比較して無関係になります。

于 2012-05-02T12:59:48.567 に答える