Avatar billede encorez Nybegynder
19. november 2013 - 10:27 Der er 12 kommentarer og
1 løsning

Deling af data til processer

Hej

Jeg har en text fil på f.eks. 80MB med data. Den skal jeg gennemgå f.eks. 10000 gange for at analysere de data. For at bruge alle CPUer/processorer på computeren spreder jeg disse gennemgange ud på processer som forslået i dette spørgsmål
http://www.eksperten.dk/spm/982009

Det virker fint. Men hver gang programmet skal gennemgå datafilen med
Scanner scanner = new Scanner(new File("data-fil.txt"));
det tager lige nu 7-8 milisekunder hver gang.

og derefter går jeg igennem filen linie for linie med:
Timestamp Y
while(scanner.hasNext()){
Timestamp X
når jeg indlæser FØRSTE linie, går der 0-2 milisekunder fra Y til X.

Spørgsmålet er om man kan indlæse en datafil i hver enkelt gennemgang mere effektivt end dette.
Jeg kører det i IntelliJ IDEA. Jeg ved ikke om den kan finde ud af at chache, så når først den har indlæst filen én i hukommelsen, så behøver den ikke læse den fra disken igen?!

Men ellers om det ville være en ide at læse filen én gang til en String eller andet, og gøre den tilgængelig for den andre processor som skal bruge den.

Hvis I mener det kan gøres mere effektivt, så vil jeg meget meget gerne se eksempler eller referencer til eksempler.

På forhånd mange tak :)
Avatar billede arne_v Ekspert
19. november 2013 - 14:32 #1
Du skal helt klart kun laese filen en gang. 80 MB kan sagtens vaere i memory.

Du kan gemme linier i en ArrayList<String>.

Eller maaske bedre i en ArrayList<DinKlasse>.
Avatar billede encorez Nybegynder
19. november 2013 - 21:23 #2
Lyder godt, men når jeg så har lavet den ArrayList, er det så nemt nok at fange den inde i processerne hvor den skal bruges? Kan skrive ultra kort eksempel til at illustrere?
Avatar billede arne_v Ekspert
19. november 2013 - 21:35 #3
Hvis du koerer traade er det nemt at sende en ref til den ArrayList med over i constructor til den klasse hvis instans er en traad.
Avatar billede encorez Nybegynder
19. november 2013 - 22:01 #4
Jeg bruger den metode du foreslog i det spørgsmål jeg referer til.

Men kan du skrive et kort eksempel på hvordan jeg felter det ind det du foreslår?
Avatar billede arne_v Ekspert
20. november 2013 - 03:50 #5
Er det ikke bare en kombinering af http://www.eksperten.dk/spm/982009#reply_8065086 (kommentar #2) og http://www.eksperten.dk/spm/982009#reply_8066125 (kommentar #15) hvor Param ikke er en int men den ArrayList<Data> som du indlaeser i main?
Avatar billede encorez Nybegynder
21. november 2013 - 10:08 #6
Det er sikkert en kombination ja, jeg skal bare finde ud af hvordan og rette til, da jeg er ny i Java verden :)

Jeg har omskrevet Param til String istedet da det er det jeg "sender" videre til trådene, som nedenstående.

String testdata = "abcd";
workres[counter] = es.submit(new WorkUnit(new ParamAndResult(testdata)));

Så kan jeg både sende en String og den reference til data i bufferen? Og hvordan så
Avatar billede arne_v Ekspert
22. november 2013 - 03:38 #7
Til inspiration:


import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class LoadMTRun {
    private static List<Data> load(Reader rdr) throws IOException {
        List<Data> res = new ArrayList<Data>();
        BufferedReader br = new BufferedReader(rdr, 1000000);
        String line;
        while((line = br.readLine()) != null) {
            String[] parts = line.split(",");
            int a = Integer.parseInt(parts[0]);
            int b = Integer.parseInt(parts[1]);
            int c = Integer.parseInt(parts[2]);
            res.add(new Data(a, b, c));
        }
        br.close();
        return res;
    }
    private static void analyze(List<Data> lst) throws InterruptedException, ExecutionException {
        //long t1 = System.currentTimeMillis();
        //ExecutorService es = Executors.newFixedThreadPool(1);
        ExecutorService es = Executors.newFixedThreadPool(3);
        Future<ParamAndResult> avga = es.submit(new WorkUnitSumA(new ParamAndResult(lst)));
        Future<ParamAndResult> avgb = es.submit(new WorkUnitSumB(new ParamAndResult(lst)));
        Future<ParamAndResult> avgc = es.submit(new WorkUnitSumC(new ParamAndResult(lst)));
        System.out.printf("Averages = %.1f %.1f %.1f\n", avga.get().getResult(), avgb.get().getResult(), avgc.get().getResult());
        //long t2 = System.currentTimeMillis();
        //System.out.printf("Time = %d ms\n",  t2 - t1);
       
    }
    private static void process(String fnm) throws IOException, InterruptedException, ExecutionException {
        List<Data> lst = load(new FileReader(fnm));
        analyze(lst);
    }
    private static void setup(String fnm, int n) throws IOException {
        Random rng = new Random();
        try(PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(fnm), 1000000)))
        {
            for(int i = 0; i < n; i++) {
                int a = rng.nextInt(1000);
                int b = rng.nextInt(1000000);
                int c = rng.nextInt(1000000000);
                pw.printf("%d,%d,%d\n", a, b, c);
            }
        }
    }
    private static final String FNM = "/work/test.txt";
    private static final int NNUM = 10000000;
    public static void main(String[] args) throws Exception {
        setup(FNM, NNUM);
        process(FNM);
    }
}

class WorkUnitSumA implements Callable<ParamAndResult> {
    private ParamAndResult par;
    public WorkUnitSumA(ParamAndResult par) {
        this.par = par;
    }
    public ParamAndResult call() throws Exception {
        List<Data> lst = par.getParam();
        double res = 0;
        for(Data o : lst) {
            res += o.getA();
        }
        res /= par.getParam().size();
        par.setResult(res);
        return par;
    }
}

class WorkUnitSumB implements Callable<ParamAndResult> {
    private ParamAndResult par;
    public WorkUnitSumB(ParamAndResult par) {
        this.par = par;
    }
    public ParamAndResult call() throws Exception {
        List<Data> lst = par.getParam();
        double res = 0;
        for(Data o : lst) {
            res += o.getB();
        }
        res /= par.getParam().size();
        par.setResult(res);
        return par;
    }
}

class WorkUnitSumC implements Callable<ParamAndResult> {
    private ParamAndResult par;
    public WorkUnitSumC(ParamAndResult par) {
        this.par = par;
    }
    public ParamAndResult call() throws Exception {
        List<Data> lst = par.getParam();
        double res = 0;
        for(Data o : lst) {
            res += o.getC();
        }
        res /= par.getParam().size();
        par.setResult(res);
        return par;
    }
}

class ParamAndResult {
    private List<Data> param;
    private double result;
    public ParamAndResult(List<Data> param) {
        this.param = param;
        this.result = 0;
    }
    public List<Data> getParam() {
        return param;
    }
    public double getResult() {
        return result;
    }
    public void setResult(double result) {
        this.result = result;
    }
}

class Data {
    private int a;
    private int b;
    private int c;
    public Data(int a, int b, int c) {
        this.a = a;
        this.b = b;
        this.c = c;
    }
    public int getA() {
        return a;
    }
    public void setA(int a) {
        this.a = a;
    }
    public int getB() {
        return b;
    }
    public void setB(int b) {
        this.b = b;
    }
    public int getC() {
        return c;
    }
    public void setC(int c) {
        this.c = c;
    }
}
Avatar billede encorez Nybegynder
24. november 2013 - 20:06 #8
Mange tak. Jeg sidder nu og prøver at gennemskue dette med hvad jeg har nu og har selvfølgelig lige et par spørgsmål.
"class Data" er naturligvis de data der gemmes i hukommelsen og bruges igen og igen. Istedet for 3 int værdier som du har i eksemplet, kan man så både have en int, en String, en Bigdecimal osv?

I ParamAndResult bliver den lidt tricky.
Lige nu har jeg både en String som Param og String som result.
Når jeg danner mine WorkUnits så har jeg brug for at sende 2 parametre med, både en String (som er den kombination af værdi jeg skal afprøve) og List<data> med referencen til mine data.
Så hvordan håndterer jeg det?
Avatar billede arne_v Ekspert
24. november 2013 - 23:27 #9
Du kan sagtens have felter af forskellige i din data klasse.

Du kan lade ParamAndResult have baade en param1 og en param2.
Avatar billede encorez Nybegynder
29. november 2013 - 08:40 #10
Jeg får en fejl i class Data. "Data" understreges og jeg får fejlen "Data is already defined in this compilation unit".

Kan du sige hvordan jeg retter hvad der er galt?
Avatar billede encorez Nybegynder
29. november 2013 - 09:05 #11
Jeg løste det ved at ændre navnet fra Data til Dataset. Mystisk hvorfor den ikke ville acceptere Data
Avatar billede encorez Nybegynder
08. december 2013 - 19:39 #12
Det virker :)  det har speedet min funktionen en hel del op, så mange tak for hjælpen.

Læg et svar som tak for hjælpen
Avatar billede arne_v Ekspert
08. december 2013 - 21:25 #13
svar
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester