2016-10-17 18 views
4

我對斯卡拉非常陌生,我想用相同的性能水平來翻譯我的Java代碼。斯卡拉點產品相對於Java非常慢

給定n個浮點向量和一個額外的向量,我必須計算所有n點產品並獲得最大值。

使用Java是我

public static void main(String[] args) { 

    int N = 5000000; 
    int R = 200; 
    float[][] t = new float[N][R]; 
    float[] u = new float[R]; 

    Random r = new Random(); 

    for (int i = 0;i<N;i++) { 
     for (int j = 0;j<R;j++) { 
      if (i == 0) { 
       u[j] = r.nextFloat(); 
      } 
      t[i][j] = r.nextFloat(); 
     } 
    } 

    long ts = System.currentTimeMillis(); 
    float maxScore = -1.0f; 

    for (int i = 0;i < N;i++) { 
     float score = 0.0f; 
     for (int j = 0; i < R;i++) { 
      score += u[j] * t[i][j]; 
     } 
     if (score > maxScore) { 
      maxScore = score; 
     } 

    } 

    System.out.println(System.currentTimeMillis() - ts); 
    System.out.println(maxScore); 

} 

的計算時間與我的機器上6毫秒非常簡單。

現在我有斯卡拉

val t = Array.ofDim[Float](N,R) 
val u = Array.ofDim[Float](R) 

// Filling with random floats like in Java 

val ts = System.currentTimeMillis() 
var maxScore: Float = -1.0f 

for (i <- 0 until N) { 
    var score = 0.0f 
    for (j <- 0 until R) { 
    score += u(j) * t(i)(j) 
    } 
    if (score > maxScore) { 
    maxScore = score 
    } 

} 

println(System.currentTimeMillis() - ts) 
println(maxScore); 

上面的代碼需要比第二我的機器上更做到這一點。 我的想法是,斯卡拉沒有原始數組結構,如Java中的float [],並被集合取代。索引i處的訪問似乎比使用Java中的基本數組的操作要慢。

下面的代碼是更慢:

val maxScore = t.map(r => r zip u map Function.tupled(_*_) reduceLeft (_+_)).max 

這需要26S

我應該如何有效地在我的2個陣列迭代計算呢?

非常感謝

+2

你可以在Scala中使用數組...... Scala示例中定義了't'和'u'的地方/如何? –

+0

哎呀,錯過了! 剛剛更新了文章 – ogen

+1

@ogen與您的問題無關,但作爲一個附註,'0直到N'比'0到(N-1)更具慣用性' – fxlae

回答

20

好吧,抱歉地說,但這裏的奇怪的是你的Java實現有多快,你的斯卡拉一個並不怎麼慢是 - (!)6ms的遍歷10十億個細胞聽起來好得是真的 - 事實上 - 您在Java實現,使這個代碼有一個錯字做的要少得多:

,而不是for (int j = 0; j < R;j++),你有for (int j = 0; i < R;i++) - 這使得內環運行只有200倍,而不是10億 ...

如果你解決了這個問題 - Scala和Java的性能是可比的。

這,順便說一句,其實是斯卡拉的優勢 - 這是很難得到for (j <- 0 until R)錯誤:)

+3

聖!在你解答**之後,我花了幾秒鐘才注意到錯字**。好的趕上! –

+0

LOL:D我開始讀取生成的scala字節碼,因爲它對我來說太奇怪了。這只是在java代碼中的一個錯字:D:D:D – NieMaszNic

+1

我完全同意這是Scala的一個優點。這也是爲什麼我和j實際上不應該在任何語言中一起用作循環索引的原因。 :) x和y通常更容易看到這些東西。 –

3

真正的問題只是一個錯字(如Tzach瑣提到),但如果你想改善的表現,那麼你可以做更多的impretive方式:

var i = 0 
while (i < N) { 
    var j = 0 
    var score = 0.0f 
    val t1: Array[Float] = t(i) 
    while (j < R) { 
    score += u(j) * t1(j) 
    j += 1 
    } 
    if (score > maxScore) { 
    maxScore = score 
    } 

    i += 1 
} 

這段代碼的運行速度比換理解的版本快約10-20%。

或!您可以使用「相提並論」,使第一陣列並行和while循環裏面使用地圖:

val maxScore = t.par.map({ 
    arr => 
    var score = 0.0f 
    var j = 0 
    while (j < R) { 
     score += u(j) * arr(j) 
     j += 1 
    } 
    score 
}).max 

此代碼運行的2-3倍我的機器上快於Java版本! 親自試一試! :)祝你好運