2016-06-18 41 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

相关问题