読者です 読者をやめる 読者になる 読者になる

Rでマルチコア計算

R言語上級ハンドブックのChapter2 Section25「マルチコアで計算を繰り返し行う」でmulticoreパッケージを使った演算を行ってる。Windows環境ではこのパッケージが動かないので、ここにメモ。
計算はすべてMacでやってます。

実行時間を比較

テキストではモンテカルロ積分を使った演算をして、マルチコアを用いるmclapply、sapply、forの3通りの実装で速度を比較しています。

# テストデータを作成
> x.num <- 100
> x <- seq(0.1, 2.5, length = x.num)
> m <- 100000
> u <- runif(m)

# 並列化して確率密度関数を計算
> system.time(mclapply(x,
+   function(x) {
+     g <- x * exp( -(u * x)^2 / 2)
+     mean(g) / sqrt(2 * pi) + 0.5
+   }
+ ))
   ユーザ   システム       経過  
    38.962      7.810      0.152 

# 並列化せずに確率密度関数を計算 (sapply)
> system.time(sapply(x,
+   function(x) {
+     g <- x * exp( -(u * x)^2 / 2)
+     mean(g) / sqrt(2 * pi) + 0.5
+   }
+ ))
   ユーザ   システム       経過  
     0.228      0.126      0.354 

# 並列化せずに確率密度関数を計算 (for)
> system.time(numeric(x.num)
+ for ( i in 1:x.num ) {
+   g   <- x[i] * exp( -(u * x[i])^2 / 2)
+   cdf[i] <- mean(g) / sqrt(2 * pi) + 0.5
+ })
   ユーザ   システム       経過  
     0.226      0.110      0.335 

経過時間(テキスト137ページの表のelapsed)を比較するとmclapplyが倍以上速い。

mclapply sapply for
経過時間 0.152 0.354 0.335

計算してるiMacは4コアなので並列効率はそこそこ?

sapplyとforが似たり寄ったり

もっとsapplyのほうが速いって聞いてたんですけど。というわけでもうちょっと計算してみた。

# テストデータを作成
> x.num <- 100
> x <- seq(0.1, 2.5, length = x.num)
> m <- 1000000
> u <- runif(m)
> mc <- numeric(100)
> for(i in 1:100){
+     t <- system.time(mclapply(x,
+         function(x) {
+             g <- x * exp( -(u * x)^2 / 2)
+             mean(g) / sqrt(2 * pi) + 0.5
+         }
+     ))
+     mc[i] = t[3]
+ }

mを10倍にして100回施行。これをmclapply、sapply、forについてそれぞれ実行して、それぞれの経過時間のmeanとvarを計算。

mclapply sapply for
mean 1.88988 5.05238 5.06731
var 0.0006068137 0.01092876 0.008823186

せっかくなんでグラフにしてみた。

うーん、sapplyとforが変わらないな。