Выполнение математических расчетов по текстовому файлу Java - PullRequest
4 голосов
/ 18 апреля 2011

Я беру в текстовом файле около 60000 строк координат точек (я ожидаю, что скоро увеличу масштаб) и выполняю расстояние Махаланобиса от каждой точки до любой другой точки, и выводу результат в виде текстового файла. Это означает, что мои результаты будут иметь длину почти 3 600 000 000 строк. Моя программа создает около 60 000 строк каждые 1 или 2 секунды.

Правильно ли я считаю, что мой код не может быть многопоточным? Есть ли лучший способ кодирования этого алгоритма? Как люди справляются с такими процессами?

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

    public class Coord {
        public int a,b,c,d,e,f;


    public static void main(String[] args) throws IOException {
        PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("/Users/evanlivingston/2a.txt", true)));
        Scanner sc = new Scanner(new File("/Users/evanlivingston/1.txt"));
        List<Coord> coords = new ArrayList<Coord>();{


            // for each line in the file
            while(sc.hasNextLine()) {
                String[] numstrs = sc.nextLine().split("\\s+"); 

                Coord c = new Coord();


                c.a = Integer.parseInt(numstrs[1]);
                c.b = Integer.parseInt(numstrs[2]);
                c.c = Integer.parseInt(numstrs[3]);
                c.d = Integer.parseInt(numstrs[4]);
                c.e = Integer.parseInt(numstrs[5]);
                c.f = Integer.parseInt(numstrs[6]);

                coords.add(c);

            }


// now you have all coords in memory
    int counter = 0;        {
for(int i=0; i<coords.size(); i++ ) 
    for( int j=0; j<coords.size(); j++, counter++ ) 
    {
        Coord c1 = coords.get(i);
        Coord c2 = coords.get(j);
        double foo = ((c1.a - c2.a) * (c1.a - c2.a)) *1 ;
        double goo = ((c1.b - c2.b) * (c1.b - c2.b)) *1 ;
        double hoo = ((c1.c - c2.c) * (c1.c - c2.c)) *2 ;
        double joo = ((c1.d - c2.d) * (c1.d - c2.d)) *2 ;
        double koo = ((c1.e - c2.e) * (c1.e - c2.e)) *4 ;
        double loo = ((c1.f - c2.f) * (c1.f - c2.f)) *4 ;
        double zoo = Math.sqrt(foo + goo + hoo + joo + koo + loo);

        out.println(counter + "; " + i + " " + j + " " + zoo);
       System.out.println(counter + "; " + i + " " + j + " " + zoo);

    }
    out.flush();
    out.close();
            }
        }
    }   
}

Мой входной файл выглядит как

0 0 0 0 0 0 0

1 0 0 0 0 0 1

....

59318 12 2 12 2 12 2

Первый номер - заполнитель. Это список всех комбинаций с заменой, ограниченных суммами, которые вы видите в последней строке.

Теперь кажется, что расчеты займут около 16 часов, что все еще кажется слишком длинным. Не говоря уже о том, что я оцениваю окончательный вывод текста примерно в 120 ГБ.

Ответы [ 3 ]

7 голосов
/ 18 апреля 2011

Ваш код очень неэффективен.Вы перечитываете файл второй раз в каждой строке (!!!) в файле.Дисковый ввод-вывод очень медленный.

Что вам нужно сделать, это загрузить файл в проанализированную структуру памяти (массив значений типа double), а затем выполнить над ним вложенный цикл.

Правильно ли я считаю, что мой код не может быть многопоточным?

Вы ошиблись.Эта задача очень выиграет от многопоточности.Но ваш первый приоритет - избавиться от повторяющихся операций ввода-вывода.Я предполагаю, что тогда производительность будет достаточно хорошей.

ОБНОВЛЕНИЕ до ОБНОВЛЕНИЕ

Переписан ваш класс в несколько потоков (по умолчанию 4).Недостаток: строки в выходном файле записаны не по порядку, хотя, используя утилиту сортировки unix, вы можете при необходимости отсортировать их после вычисления.И A-> B, и B-> A по-прежнему рассчитываются, так как я не смог придумать простой способ сохранить результат A-> B за исключением использования 64-битной Java и установки 64 ГБ ОЗУ.

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Coord {
    public int a, b, c, d, e, f;

    private static class CoordsThread extends Thread {
        private int start;
        private int end;
        private List<Coord> coords;
        private PrintWriter out;

        public CoordsThread(int start, int end, List<Coord> list, PrintWriter out) {
            this.start = start;
            this.end = end;
            this.coords = list;
            this.out = out;

            // last block can be shorter
            if( this.end > this.coords.size() ) this.end = this.coords.size();
        }

        public void run() {
            System.out.println("started thread "+getName()+" for ["+start+";"+end+")");
            for (int i = start; i < end; i++) {
                for (int j = 0; j < coords.size(); j++ ) {
                    Coord c1 = coords.get(i);
                    Coord c2 = coords.get(j);
                    double foo = ((c1.a - c2.a) * (c1.a - c2.a)) * 1;
                    double goo = ((c1.b - c2.b) * (c1.b - c2.b)) * 1;
                    double hoo = ((c1.c - c2.c) * (c1.c - c2.c)) * 2;
                    double joo = ((c1.d - c2.d) * (c1.d - c2.d)) * 2;
                    double koo = ((c1.e - c2.e) * (c1.e - c2.e)) * 4;
                    double loo = ((c1.f - c2.f) * (c1.f - c2.f)) * 4;
                    double zoo = Math.sqrt(foo + goo + hoo + joo + koo + loo);

                    synchronized (out) {
                        out.println(i*coords.size()+j + "; " + i + " " + j + " " + zoo);
                    }
                }
            }
            System.out.println("completed thread "+getName());
        }
    }

    public static void main(String[] args) throws Exception {
        PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("2.txt")));
        Scanner sc = new Scanner(new File("1.txt"));
        List<Coord> coords = new ArrayList<Coord>();

        // for each line in the file
        while (sc.hasNextLine()) {
            String[] numstrs = sc.nextLine().split("\\s+");

            Coord c = new Coord();

            c.a = Integer.parseInt(numstrs[1]);
            c.b = Integer.parseInt(numstrs[2]);
            c.c = Integer.parseInt(numstrs[3]);
            c.d = Integer.parseInt(numstrs[4]);
            c.e = Integer.parseInt(numstrs[5]);
            c.f = Integer.parseInt(numstrs[6]);

            coords.add(c);
        }

        System.out.println("total lines read: "+coords.size());

        int threadsCount = 4;
        List<Thread> ths = new ArrayList<Thread>();

        int blockSize = coords.size()/threadsCount+1;
        for( int i=0; i<threadsCount; ++i  ) {
            CoordsThread ct = new CoordsThread(i*blockSize, (i+1)*blockSize, coords, out);
            ct.setName("Block"+i);
            ths.add(ct);
        }

        for (Thread th : ths) {
            th.start();
        }

        for (Thread th : ths) {
            th.join();
        }

        out.flush();
        out.close();
    }
}
1 голос
/ 18 апреля 2011

Вы читаете файл 1.txt слишком много раз.Прочитайте его один раз, сохраните в массиве типа int[][].

Также попробуйте увеличить размер экземпляра BufferedWriter.

Кроме того, позвольте экземпляру Scanner работатьна BufferedInputstream с правильным набором символов.

1 голос
/ 18 апреля 2011

Вы делаете много повторяющихся операций ввода-вывода, очень дорого, дороже на порядок, чем любые вычисления, которые вы делаете.

Кроме того, ваш проблемный домен очень хорошо вписывается в сценарий сопоставления / сокращения, который не только прост в многопоточности, но вы также сможете распределять вычисления по нескольким машинам.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...