2016-06-18 40 views
0

我得到了一個逗號分隔的文件,其中包含10 977 120個隨機數(60 MB),其中我得到了總和。這項任務是關於同時進行這項工作,並因此儘可能禁食。長話短說,我將文本文件加載到一個字符串數組中。我的下一個想法是,然後將這個數組分成四個小塊,然後對於每個塊,有一個線程來總結這個塊。與copyOfRange分割數組時出現奇怪的運行時間

奇怪的是,當我將列表分成4個部分時,我的運行時間差別很大。

我有看起來像這樣的方法:

public void splitNumbers(String[] numbers){ 
    int size = numbers.length; 
    String[][] numberssplit = new String[4][]; 
    numberssplit[0] = Arrays.copyOfRange(numbers, 0, size/4); 
    numberssplit[1] = Arrays.copyOfRange(numbers, (size/4)+1, size/2); 
    numberssplit[2] = Arrays.copyOfRange(numbers, (size/2)+1, 3*(size/4)); 
    numberssplit[3] = Arrays.copyOfRange(numbers, (3*(size/4))+1, size-1); 
    //MS: 2750 
} 

以上大約需要2750毫秒

numberssplit[0] = Arrays.copyOfRange(numbers, 0, size/4); 
numberssplit[1] = Arrays.copyOfRange(numbers, (size/4)+1, size/2); 
//numberssplit[2] = Arrays.copyOfRange(numbers, (size/2)+1, 3*(size/4)); 
//numberssplit[3] = Arrays.copyOfRange(numbers, (3*(size/4))+1, size-1); 
MS: 5 

然而,只有拆分兩個部分,採用5個MS,使它看起來就像是最後兩件需要更長的時間。

只有分裂第三部分以2毫秒

//numberssplit[0] = Arrays.copyOfRange(numbers, 0, size/4); 
//numberssplit[1] = Arrays.copyOfRange(numbers, (size/4)+1, size/2); 
numberssplit[2] = Arrays.copyOfRange(numbers, (size/2)+1, 3*(size/4)); 
//numberssplit[3] = Arrays.copyOfRange(numbers, (3*(size/4))+1, size-1); 
//MS: 2 

也是如此。第四部分時,它的唯一的一塊被拆分。

//numberssplit[0] = Arrays.copyOfRange(numbers, 0, size/4); 
//numberssplit[1] = Arrays.copyOfRange(numbers, (size/4)+1, size/2); 
//numberssplit[2] = Arrays.copyOfRange(numbers, (size/2)+1, 3*(size/4)); 
numberssplit[3] = Arrays.copyOfRange(numbers, (3*(size/4))+1, size-1); 
//MS: 2 

最後,最後兩個未加註釋,需要2927毫秒

//numberssplit[0] = Arrays.copyOfRange(numbers, 0, size/4); 
//numberssplit[1] = Arrays.copyOfRange(numbers, (size/4)+1, size/2); 
numberssplit[2] = Arrays.copyOfRange(numbers, (size/2)+1, 3*(size/4)); 
numberssplit[3] = Arrays.copyOfRange(numbers, (3*(size/4))+1, size-1); 
//MS: 2927 

看來當numbersplit[2]numbersplit[3]是結合它需要大量的再像,但是這是爲什麼?顯然,java在幕後做了一些魔術,但我無法看到邏輯。那麼發生了什麼?

+1

60MB文件中有多少個String對象?基本上,你的數字數組有多長?多少內存分配給你的jvm? –

+0

10 977 120個號碼^^,我不確定 – Jazerix

回答

1

簡答題:用-verbose:gc運行你的項目,輸出會給你一個完整的答案。

龍答:

我做了使用你的代碼的第一個塊的測試。 首先你會在這些範圍內寬鬆的一個數字:

(size/4)+1, size/2 
(size/2)+1, 3*(size/4) 

和兩個數字在這裏:

(3*(size/4))+1, size-1 

說明here

從 - 範圍的初始索引被複制,包括 到 - 要複製的範圍的最終索引,獨佔

作爲Array的複雜性。copyOfRange是(O(n)),這四個部分之間不應該有任何時間差。 但是,如果您看到類似這樣的內容,則意味着由內存分配引起的內存問題。

看看這個:

package testproject; 

import java.util.Arrays; 

public class TestProject { 

    public static void main(String[] args) { 
     String[] numbers = getNumbers(0, 10000000); 

     long timestamp = System.currentTimeMillis(); 
     System.out.println("Starting split"); 
     String[][] splitted = splitNumbers(numbers); 
     System.out.println(System.currentTimeMillis() - timestamp); 

     timestamp = System.currentTimeMillis(); 
     System.out.println("Starting split"); 
     splitted = splitNumbers(numbers); 
     System.out.println(System.currentTimeMillis() - timestamp); 
    } 

    public static String[] getNumbers(int from, int to){ 
     String[] res = new String[to-from]; 
     for(int i=0; i<(to-from); i++){ 
      res[i] = Integer.toString(from + i); 
     } 
     return res; 
    } 

    public static String[][] splitNumbers(String[] numbers){ 
     int size = numbers.length; 
     String[][] numberssplit = new String[4][]; 
     numberssplit[0] = Arrays.copyOfRange(numbers, 0, size/4); 
     numberssplit[1] = Arrays.copyOfRange(numbers, (size/4), size/2); 
     numberssplit[2] = Arrays.copyOfRange(numbers, (size/2), 3*(size/4)); 
     numberssplit[3] = Arrays.copyOfRange(numbers, (3*(size/4)), size); 
     return numberssplit; 
    } 
} 

下面我們就來splitNumbers通話兩次。

結果在我的電腦:

Starting split 
    15 
    Starting split 
    [GC (Allocation Failure) 626829K->625997K(764928K), 0.2908820 secs] 
    [Full GC (Ergonomics) 625997K->625210K(1039872K), 3.2126996 secs] 
    3510 

所以,是的,正如你在這裏看到我們隱藏調用垃圾收集器。 他們造成你的問題。

+0

啊,這太棒了,謝謝你清理這個! – Jazerix

0

考慮不需要複製數據的方法。

例如,給每個任務的原始數組,但工作範圍。

另一種方法是將其表示爲列表並使用subList方法,該方法返回視圖而不是副本。

+0

我同意,更好的想法可能是在閱讀文件時直接拆分它,但是,我仍然在尋找關於爲什麼會發生上述情況的答案,copyOfRange ,這是我的好奇心:) – Jazerix

+0

正如我在上面的評論中暗示的,我的猜測是你的問題與jvm中的內存管理有關。 copyOfRange是一個本地調用,用於將數組內的指針複製到另一個數組。我猜這些數組相當大,這需要分配大量連續的內存塊。根據內存的當前狀態,這可能需要很多工作。 –

+0

這是有道理的^^,然而這只是當前兩個拆分需要4-5毫秒,而最後兩個拆分時,當它們大致相同的大小時,似乎很奇怪。 – Jazerix

相關問題