我有一个逗号分隔的文件,有10 977 120个随机数(60 MB),其中我得到了总和。任务是同时做到这一点,因此可能以禁食的方式。长话短说,我将文本文件加载到字符串数组中。我的下一个想法是将这个数组分成四个较小的部分,然后对于每个部分,都有一个对该部分求和的线程。
奇怪的是,当我将列表分成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,在幕后做了一些魔术,但我无法看到逻辑。那么发生了什么?
答案 0 :(得分:1)
简短回答:使用-verbose:gc运行项目,输出将为您提供完整的答案。
答案很长:
我使用代码的第一个块进行了测试。 首先,你将在这些范围内松开一个数字:
(size/4)+1, size/2
(size/2)+1, 3*(size/4)
这里有两个数字:
(3*(size/4))+1, size-1
解释here:
from - 要复制的范围的初始索引(包括) to - 要复制的范围的最终索引,独占
由于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
所以是的,正如你在这里看到的,我们隐藏了对垃圾收集器的调用。 它们会引起你的问题。
答案 1 :(得分:0)