1

我需要计算平均值并从一个大文件中提取一些数字的根:

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,这会是一个解决方案吗?

4

4 回答 4

3

您必须预先接受一些重要的事情 -您处理数据的速度将无法比从文件中读取数据的速度更快。因此,第一次阅读整个文件并接受您不会对此进行改进需要多长时间。

也就是说-您是否考虑过ForkJoinPool

于 2013-11-11T23:11:22.417 回答
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 = ....
于 2013-11-11T23:01:31.853 回答
0

我认为这是可能的。

  1. int offset =(文件大小/线程数)
  2. 创建 n 个线程
  3. 每个线程从偏移*线程号开始读取。例如线程0从字节0开始读取,线程1从偏移量*1开始读取,线程2从偏移量*2开始读取
  4. 如果线程 num != 0,请继续阅读,直到您遇到换行符 - 从那里开始。
  5. 将每个线程的平均值相加。保存到“thread_average”之类的。
  6. 当所有线程都完成时,总平均值 = 所有“thread_average”变量的平均值
  7. 总平均变量的平方根。

它需要一些混乱来确保线程不会读得太远到文件的另一个线程块中,但应该是可行的

于 2013-11-11T23:01:46.093 回答
0

不,没有办法并行化。尽管您可以做一些看起来像是在使用线程的事情,但结果会过于复杂,但仍以与以前大致相同的速度运行。

这样做的原因是文件访问是并且必须是单线程的,除了从文件中读取之外,您所做的只是两个添加操作。因此,在最好的情况下,这些添加操作可以并行化,但是由于这些操作几乎不需要执行时间,因此增益最多只有 5% - 10%。而那个时间被线程创建和维护否定(或更糟)。

一旦你可以做的事情是加快速度,那就是删除你将东西放入列表的部分(假设你以后不需要这些值)。

 while (sc.hasNextInt()) {
   res += sc.nextInt();
   ++c;
 }

 mean = res / c;
于 2013-11-11T23:34:44.487 回答