2014-06-25 62 views
1

我試圖將一個函數「映射」到一個數組上。但是,在嘗試簡單功能和複雜功能時,並行版本總是比串行版本慢。如何提高R中的並行計算性能?如何比串行版本更快地進行並行操作?

簡單平行例如:

library(parallel) 

# Number of elements 
arrayLength = 100 
# Create data 
input = 1:arrayLength 

# A simple computation 
foo = function(x, y) x^y - x^(y-1) 

# Add complexity 
iterations = 5 * 1000 * 1000 

# Perform complex computation on each element 
compute = function (x) { 
    y = x 
    for (i in 1:iterations) { 
    x = foo(x, y) 
    } 
    return(x) 
} 

# Parallelized compute 
computeParallel = function(x) { 
    # Create a cluster with 1 fewer cores than are available. 
    cl <- makeCluster(detectCores() - 1) # 8-1 cores 
    # Send static vars & funcs to all cores 
    clusterExport(cl, c('foo', 'iterations')) 
    # Map 
    out = parSapply(cl, x, compute) 
    # Clean up 
    stopCluster(cl) 
    return(out) 
} 

system.time(out <- compute(input)) # 12 seconds using 25% of cpu 
system.time(out <- computeParallel(input)) # 160 seconds using 100% of cpu 
+1

集羣的初始化需要時間。你有沒有嘗試初始化你的功能? –

+0

這不是一個公平的比較,但我只是試了一下。沒有實質性變化。如果初始化可以解釋數量級差異,我會感到驚訝。 – sharoz

+0

我並沒有太多的使用這些並行程序包,但字面上每次都有一個關於爲什麼並行化比串行化慢的問題,因爲分割任務的開銷主宰了任務本身的複雜性。 – joran

回答

1

的問題是,你權衡向量化進行並行的所有,這是一個糟糕的交易。您需要保持儘可能多的矢量化,以期對這類問題進行並行化改進。

並行包中的pvec函數可以很好地解決這類問題,但它在Windows上並不支持。在Windows上工作的更通用的解決方案是使用foreach和itertools包,其中包含可用於迭代各種對象的函數。下面是一個使用了「isplitVector」功能,爲每個工人建立一個子向量的例子:

library(doParallel) 
library(itertools) 
cl <- makeCluster(detectCores() - 1) 
registerDoParallel(cl) 
computeChunk <- function(x) { 
    foreach(xc=isplitVector(x, chunks=getDoParWorkers()), 
      .export=c('foo', 'iterations', 'compute'), 
      .combine='c') %dopar% { 
    compute(xc) 
    } 
} 

這可能還是比不上很好純矢量版本,但它應該得到的「迭代」的價值更好增加。它可能實際上有助於減少工人的數量,除非「迭代」的價值非常大。

+0

我想我認爲分塊是由'parSapply'自動完成的。這降低了時間低於連續時間。 – sharoz

0

parSapply將單獨運行的input每個元件上的功能,這意味着你正在放棄你從向量化寫方式和foo獲得compute速度。

pvec將通過塊在多個核上運行矢量化函數。試試這個:

system.time(out <- pvec(input, compute, mc.cores=4)) 
+0

不幸的是,我的功能在Windows上不支持mc.cores> 1 – sharoz

相關問題