我需要计算平均值并从一个巨大的文件中提取一些数字的根:
1, 2, 3, 4, 5,\n
6, 7, 8, 9, 10,\n
11, 12, 13, 14,15,\n
...
这是代码:
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Scanner;
public class App1{
int res, c;
double mean, root;
ArrayList list = new ArrayList();
public App1() {
// einlesen
Scanner sc = null;
try {
sc = new Scanner(new File("file.txt")).useDelimiter("[,\\s]+");
} catch (FileNotFoundException ex) {
System.err.println(ex);
}
while (sc.hasNextInt()) {
list.add(sc.nextInt());
res += (int) list.get(c);
c++;
}
sc.close();
// Mean
mean = res / list.size();
// Root
root = Math.sqrt(mean);
System.out.println("Mean: " + mean);
System.out.println("Root: " + root);
}
public static void main(String[] args) {
App1 app = new App1();
}
}
有没有办法并行化它?
在计算平均值之前,我需要所有数字,因此一个线程无法计算,而另一个线程仍在从文件中提取数字。
提取根也是一样的:如果尚未计算平均值,则线程无法从均值中提取它。
我想过Future,这会是一个解决方案吗?
答案 0 :(得分:3)
您必须事先接受一些重要的事情 - 您将无法以比从文件中读取数据更快的速度处理数据。因此,首次阅读整个文件需要多长时间,并接受您不会对此进行改进。
那就是说 - 你考虑过ForkJoinPool。
答案 1 :(得分:1)
您可以平行计算平均值,因为平均值只是总和除以计数。没有理由你不能并行地总结这些值,并计算它们,然后再进行除法。
考虑一个班级:
public class PartialSum() {
private final int partialcount;
private final int partialsum;
public PartialSum(int count, int sum) {
partialsum = sum;
partialcount = count;
public int getCount() {
return partialcount;
}
public int getSum() {
return partialsum;
}
}
现在,这可能是Future的返回类型,如Future<PartialSum>
。
因此,您需要做的是将文件分成几部分,然后将部件发送到各个线程。
每个线程计算PartialSum
。然后,当线程完成时,您可以:
int sum = 0;
int count = 0;
for(Future<PartialSum> partial : futures) {
PartialSum ps = partial.get();
sum += ps.getSum();
count += ps.getCount();
}
double mean = (double)sum / count;
double root = ....
答案 2 :(得分:0)
我认为这是可能的。
需要一些麻烦来确保线程不会读到文件的另一个线程块太远但应该可以执行
答案 3 :(得分:0)
没有办法并行化这个。虽然你可以做一些看起来像你正在使用线程的东西,但结果会过于复杂,但仍然会以与之前大致相同的速度运行。
原因是文件访问是并且必须是单线程的,除了从文件读取之外,您所做的只是两个添加操作。因此,在最好的情况下,这些添加操作可以并行化,但由于这些操作几乎没有执行时间,因此增益最多只有5%-10%。而且这个时间被线程创建和维护所否定(或更糟)。
一旦你可以采取措施加快速度,就可以删除你把东西放入列表的部分(假设你以后不需要这些值)。
while (sc.hasNextInt()) {
res += sc.nextInt();
++c;
}
mean = res / c;