Adatok leggyorsabb beolvasása

Fórumok

Sziasztok!

Egy text fájlban viszonylag nagy mennyiségű adatom van. Ezek egész számok, és egy sorban két szám helyezkedik el.

Pl. így:

1232 17
635 864
397 3766
... stb. kb. 100000 sorban.

Mi az a leggyorsabb módszer szerintetek, amivel be lehet húzni a memóriába az adatokat?

Jelenleg ezt a módszert használom:


        BufferedReader be = new BufferedReader(new FileReader("be.txt"));               
        for (int i = 0; i < m; i++) {
            s = be.readLine();
            st = new StringTokenizer(s);
            int egyik = Integer.parseInt(st.nextToken()); 
            int masik = Integer.parseInt(st.nextToken()); 
            M[egyik][masik] = 1;
        }

Hozzászólások

Egyszerre, egy Stringbe nem lehetne behúzni az egészet?

amikor ilyen cikluson belul new szerepel, az altalaban nem jo. De indits ra egy profilert!

Amikor utoljara ilyet csinaltunk, ott egy bufferbe ment be a cucc, amibol egy threadpool segitsegevel vegezte a parsolast N db szal. A teljesitmeny 20 MB/sec volt akkori vason, igaz, ott kicsit tobb dolgot kellett parsolni.

Ez SZTE és valamilyen alga vagy más biro-ra beadandó prog?
Ha igen, akkor a feladatkiírásban le van írva, hogy
Java-ban milyen módszerrel célszerű beolvasni a be.txt-t.
Ha nem, akkor bocs. :P

--
A gyors gondolat többet ér, mint a gyors mozdulat.

1) a BufferedReader-nek van olyan konstruktora, aminek megadhatod, hogy mekkora legyen az input buffer. Ergo megadsz egy jó nagy számot és az egész beugrik a BufferedReader memóriájába.

2) Létezik olyan, hogy String.split(String regex).

String[] result = "this is a test".split("\\s");

Ez pl szpészek mentén felbontja és a Tokenizer sem kell.

A kódodat nem írom át és postolom ide, mert /tabletta dolgom van (kávéügyben kell eljárnom).

Bizony, csak javadoc-ot kell olvasni.

--
"SzAM-7 -es, tudjátok amivel a Mirage-okat szokták lelőni" - Robi.

A Sun mégis inkább a split-et ajánlja:

"StringTokenizer is a legacy class that is retained for compatibility reasons although its use is discouraged in new code. It is recommended that anyone seeking this functionality use the split method of String or the java.util.regex package instead."

forrás

StringTokenizer-nek stringet csak konstruktorban tudsz megadni, metódusból nem, szóval new StringTokenizer(be.ReadLine()) minden iterációban.

Nem fogadok a kávémba mert már megittam, de sztem a tokenizer is regexp osztályokat használ.

--
"SzAM-7 -es, tudjátok amivel a Mirage-okat szokták lelőni" - Robi.

Köszönöm a hozzászólásokat!

Nemsokára nekiállok elkészíteni az új verziót. Majd közlöm, ha kész, és meg lehet köpködni, hátha segít rajta.

Addig is üdv mindenkinek!

Na, megvan.

java.util.Scanner

Direkte erre találták ki, a fogorvos is ezt ajánlja. Ezzel elkerülheted a java.io borzalmait.

Scanner sc = new Scanner(new File("myNumbers"));
      while (sc.hasNextInt()) {
          int egésszám = sc.nextInt();
          int másikegésszám = sc.nextInt();
          // ide jön a műveleted.
      }

Kérdés előtt: a nextInt() az inteket parsolja be, a whitespace-eket átugorja (úgymint \n, , \t).

--
"SzAM-7 -es, tudjátok amivel a Mirage-okat szokták lelőni" - Robi.

Egyelőre ezt csináltam. A scanner-ezést még nem tudtam figyelembe venni.


        File inFile = new File("be.txt");
        int fileSize = (int) inFile.length();
        char [] buff = new char [fileSize];
        BufferedReader be = new BufferedReader(new FileReader(inFile));    
        be.read(buff, 0, fileSize);
        be.close();

        int indexBuff = fileSize - 1;
        int [] szam = new int [2];
        int hatvany;
        for (int i = 0; i < m; i++) {
            szam[0] = 0;
            szam[1] = 0;
            for (int j = 1; j >= 0; j--) {
                while (buff[indexBuff] < '0'  ||  buff[indexBuff] > '9') {
                    indexBuff--;
                }
                hatvany = 1;
                while (buff[indexBuff] >= '0'  &&  buff[indexBuff] <= '9') {
                    szam[j] += hatvany * (buff[indexBuff] - '0');
                    indexBuff--;
                    hatvany *= 10;
                }
                indexBuff--;
            }
            M[szam[0]][szam[1]] = 1;
        }

Erről mi a véleményetek?

Így a reader fogja elvinni az egész időt. Ráadásul így leírva a működés platformfüggő, mert az alapértelmezett kódolással olvassa a fájlt, ami akármi lehet. Ne char bufferbe töltsd be, hanem byte tömbbe a karaktereket, hiszen sima ascii fájlod van. Legalábbis ha csak számok vannak benne akkor a UTF-8 is ASCII.

egy rikta bináris mátrix van a fájlban? a számok kézzel parszolását akartam én is javasolni. Így a fordító C-ben írt kód szintű optimalitásra lehet képes.
Mondjuk a szam[0] és szam[1] helyett jobb lenne szam0 és szam1, persze akkor a kódot kétszer kell leírni, de elvileg hatékonyabb lehet mert nincs indirekt címzés. Bár az egész úgyis cache-n belül marad, lehet hogy nem lesz mérhető a javulás.

buff[indexBuff]-ból nem tudom hogy a fordító csinál-e lokális átmeneti változót. Ha nem akkor ha kihozod lokálba az első lekérdezés előtt lehet hogy gyorsabb lesz. akkor nem fordul 4x a memóriához, hanem csak egyszer.

Ha valami modern hw platformon dolgozol akkor érdemes annyi szálat indítani ahány magod van (X2 ha van hyperthreading). Azért ez nem mindig jön be (mármint a hyperthreading). Egy haverom mért ilyeneket és voltak ellentmondó eredmények.

Utolsó vicces lehetőség a ciklus kihajtogatása. Ez is hozhat javulást Javában. Ennél az algoritmusnál sajnos nem nagyon lehet beleálmodni ennek a lehetőségét, ha az input fix méretűsítése nem megoldható.

Ja, és mindenképp a legújabb Javával próbálkozz, mert ilyen int műveletekre optimalizációban nagyon sokat fejlődött a JIT compiler.

Jókat mondasz, de ez nem C :) És ne is tegyünk már úgy, mintha az lenne. Egy ekkora programnál halál mindegy a szam[0], a lokális változót meg egyébként is hagyjuk. Ez a fordító dolga, pláne Java esetén. Legalábbis szerintem rohadtul nem vezet semmi jóra, ha az ember C-ben kezd Java kódot írni. Majd ahol kell az a 3%... De egyébként továbbra is: profiler.

Inkább koncentráljunk az algoritmusra: véleményem szerint ennyi adatnál a startup/rampup jóval több idő lesz, mint a feldolgozás.