BlackBoard » Design, Programmierung & Entwicklung » Programmieren » Java Datei Einlesen, performant? » Hallo Gast [Anmelden|Registrieren]
Letzter Beitrag | Erster ungelesener Beitrag Druckvorschau | An Freund senden | Thema zu Favoriten hinzufügen
Neues Thema erstellen Antwort erstellen
Zum Ende der Seite springen Datei Einlesen, performant?
Autor
Beitrag « Vorheriges Thema | Nächstes Thema »
Antiheld Antiheld ist männlich
Spagetti-Monster (Moderator)


images/avatars/avatar-1810.gif

Dabei seit: 07.08.2001
Beiträge: 755
Herkunft: Duisburg

Fragezeichen Datei Einlesen, performant?       Zum Anfang der Seite springen

Hallo,

ich habe mal eine Verständnis Frage. Gegeben ist folgender Code:
code:
1:
2:
3:
4:
5:
BufferedReader inputStream = new BufferedReader(new FileReader(fileName));	
String line = "";
while((line = inputStream.readLine()) != null){
	text += line +"\n";
}
Der Sinn ist klar, es wird eine Datei zeilenweise eingelesen. An sich ist damit auch alles vollkommen in Ordnung und bei normalen, sprich kleinen, Textdateien ist die Zeit dafür vernachlässigbar. Jetzt allerdings staune ich das es bei einer großen Datei, hier konkret 4k Zeilen, fast 10 Sekunden dauert. Das es länger dauert ist ja logisch, aber 10 Sekunden? Es ist hier nicht wirklich tragisch, das Programm dahinter ist nur zum einmaligen Gebraucht, jedoch interessiert mich das gerade.

Irgendjemand eine Idee?

Grüße
Anti

__________________
Of course, like every other man of intelligence and education I do believe in organic evolution. It surprises me that at this late date such questions should be raised.
-Woodrow Wilson, 1922 >>

28.03.2008 02:46 Antiheld ist offline E-Mail an Antiheld senden Beiträge von Antiheld suchen
Black Star Black Star ist männlich
Der Pate [Admin]


images/avatars/avatar-2158.jpg

Dabei seit: 11.12.2001
Beiträge: 2.282
Herkunft: /dev/stderr

      Zum Anfang der Seite springen

Willkommen in der Welt von Java Augenzwinkern

Ich will jetzt nicht unsachlich staenkern, aber Java und Performance schliessen sich gegenseitig weitestgehend aus.
Ich weiss auch wovon ich rede, wir haben in unserer Gruppe einige Java-Programme laufen und vergleichbarer C/C++ Code ist immer schneller und oftmals viel schneller.

Das Problem in deinem Fall konkret koennte sein, dass der string 40k mal erweitert werden muss, d.h. neuer Speicher allokiert werden muss, ...
Wie das konkret funktioniert kann ich dir nicht sagen, aber es ist nicht ausgeschlossen, dass wirklich bei jedem += neuer Speicher gesucht werden muss, was gerade bei Java ewig dauert.
Vielleicht versuchst du den String vorher auf die Groesse der Datei zu bringen und schreibst dann Zeichen fuer Zeichen in die Elemente des Strings? Der Vorteil waere, dass du nur einmal Speicher allokieren musst.

__________________
vescere bracis meis

28.03.2008 09:25 Black Star ist offline E-Mail an Black Star senden Homepage von Black Star Beiträge von Black Star suchen
PygoscelisPapua PygoscelisPapua ist männlich
BlackBoarder


images/avatars/avatar-2293.png

Dabei seit: 20.12.2003
Beiträge: 1.309
Herkunft: Kiel, Schleswig-Holstein, Germany

      Zum Anfang der Seite springen

I/O und Java ist schon immer ein schwieriges Thema gewesen, und Java tut sich hier sehr schwer (es gab mal eine Zeit da hätte ich sogar erklären können warum *seufsz*).

Die Lösung Deines Problems ist allerdings folgende:
Du nutzt den BufferedReader in der "Standardausführung" - d.h. der BufferedReader hat eine bestimmte größe (die genaue Größe weiß ich jetzt allerdings aus dem Kopf auch nicht mehr - ich glaube irgendwas um die 8.000 Bytes).

Sollte Deine Textdatei größer sein, dann kommt Java damit ins schwitzen (warum genau, kann ich Dir nicht mehr erklären - wenn es Dir wirklich wichtig ist, kann ich aber mal am WE in meinen Studienunterlagen suchen, ob ich es wiederfinde).

Das umgehen kannst Du, in dem Du die Buffer-Größe individuell auf Deine Bedürfnisse setzt. Das geht so:

code:
1:
2:
BufferedReader(FileReader, int );

Wobei int die Größe des Buffer ist (ich meine in Byte).

Hoffe, das hilft weiter.

__________________
There are only two kinds of programming languages: those people always bitch about and those nobody uses.
(Bjarne Stroustrup)
*
Moving on to pastures new
GPG Key

28.03.2008 09:39 PygoscelisPapua ist offline Homepage von PygoscelisPapua Beiträge von PygoscelisPapua suchen
Antiheld Antiheld ist männlich
Spagetti-Monster (Moderator)


images/avatars/avatar-1810.gif

Dabei seit: 07.08.2001
Beiträge: 755
Herkunft: Duisburg

Themenstarter Thema begonnen von Antiheld
      Zum Anfang der Seite springen

Ich habe das Problem jetzt gelöst, es war ungefähr das was Black Star meinte.
code:
1:
2:
3:
4:
5:
6:
BufferedReader inputStream = new BufferedReader(new FileReader(fileName));	
String line = "";
StringBuffer text = new StringBuffer();
while((line = inputStream.readLine()) != null){
	text.append(line +"\n");
}
Somit braucht das Programm nur noch 1/6 der ursprünglichen Zeit.

Ich hab es auch mit
code:
1:
BufferedReader(Reader in, int sz) 
versucht. Leider gibt es in der Java Dokumentation zu BufferedReader keine wirkliche Auskunft darüber welche Dimension sz haben soll. Mit sz = 500000 (Datei ist 484893 Bytes groß) dauerte es zumindest noch länger. Das hat mir dann gesagt der String mit der allokierung in solchem maß nicht klar kommt und hab's mit dem Stringbuffer versucht.

Danke euch beiden smile

__________________
Of course, like every other man of intelligence and education I do believe in organic evolution. It surprises me that at this late date such questions should be raised.
-Woodrow Wilson, 1922 >>

28.03.2008 10:55 Antiheld ist offline E-Mail an Antiheld senden Beiträge von Antiheld suchen
phlox81 phlox81 ist männlich
Bote des Lichts und Moderator


images/avatars/avatar-2264.jpg

Dabei seit: 19.10.2002
Beiträge: 3.028
Herkunft: Irgendwo im Nirgendwo

      Zum Anfang der Seite springen

Zitat:
Original von Black Star
Willkommen in der Welt von Java Augenzwinkern

Ich will jetzt nicht unsachlich staenkern, aber Java und Performance schliessen sich gegenseitig weitestgehend aus.
Ich weiss auch wovon ich rede, wir haben in unserer Gruppe einige Java-Programme laufen und vergleichbarer C/C++ Code ist immer schneller und oftmals viel schneller.


Mag ja genügend Beispiele geben, wo dem so ist, aber Java ist in der modernen Version durchaus nahe an C++ herangekommen. Gerade bei einer solchen Einleseoperation, sollte der Unterschied nicht allzu groß sein.

Denke das Problem liegt hier eher am "Algorithmus". Du ließt die Datei Zeilenweise aus, brauchst sie aber eigentlich am Stück. Auch in C++ würde das was dauern, weil du ja wie Black Star schon bemerkte, jedesmal neuen Speicher allokierst.
Von daher würde ich die Datei in einem Rutsch auslesen, oder sie Zeilenweise dann in einen Vector/DynArray schreiben.

phlox

__________________
Intelligenz ist eine Illusion des Menschen

phlox81.de | codenode.de
28.03.2008 11:24 phlox81 ist offline E-Mail an phlox81 senden Homepage von phlox81 Beiträge von phlox81 suchen
Antiheld Antiheld ist männlich
Spagetti-Monster (Moderator)


images/avatars/avatar-1810.gif

Dabei seit: 07.08.2001
Beiträge: 755
Herkunft: Duisburg

Themenstarter Thema begonnen von Antiheld
      Zum Anfang der Seite springen

Ich hab's nochmal umgeschrieben, jetzt lese ich alles in einem Rutsch aus. Der Grund warum ich diese zeilenweise Lösung hatte lag darin das ich früher einen ASCII String erhalten hatte, obwohl Unicode gefordert ist. Habe jetzt nochmal genauer nachgeschaut und das Problem jetzt auch beseitigt.

Ich freu mich immer wieder dabei was neues zu lernen großes Grinsen

Grüße
Anti

__________________
Of course, like every other man of intelligence and education I do believe in organic evolution. It surprises me that at this late date such questions should be raised.
-Woodrow Wilson, 1922 >>

28.03.2008 12:12 Antiheld ist offline E-Mail an Antiheld senden Beiträge von Antiheld suchen
PygoscelisPapua PygoscelisPapua ist männlich
BlackBoarder


images/avatars/avatar-2293.png

Dabei seit: 20.12.2003
Beiträge: 1.309
Herkunft: Kiel, Schleswig-Holstein, Germany

      Zum Anfang der Seite springen

Zitat:
Original von Black Star
Ich weiss auch wovon ich rede, wir haben in unserer Gruppe einige Java-Programme laufen und vergleichbarer C/C++ Code ist immer schneller und oftmals viel schneller.


Ohne dass jetzt hier in einem Java-Flamewar ausarten lassen zu wollen:

Das ist ja schön und gut was Du da sagst, und sicherlich auch richtig. Nur sollte nicht vergessen werden, dass die Anwendungsgebiete, und die Ansprüche, die die Sprachentwickler an die Sprache gestellt haben, bei den beiden Sprachen doch unterschiedlich sind, und man je nach Anwendung daher auch nicht die Wahlfreiheit hat!

Daher sind solche "C/C++ kann das besser" Kommentare meistens für die Katz (besonders ärgerlich ist sowas, wenn man das in der Uni als Vorgabe hat, und irgendwo Hilfe braucht und erstmal von 2.000 Leuten gesagt bekommt, man solle doch C++ nutzen Augen rollen ).

__________________
There are only two kinds of programming languages: those people always bitch about and those nobody uses.
(Bjarne Stroustrup)
*
Moving on to pastures new
GPG Key

28.03.2008 12:35 PygoscelisPapua ist offline Homepage von PygoscelisPapua Beiträge von PygoscelisPapua suchen
Black Star Black Star ist männlich
Der Pate [Admin]


images/avatars/avatar-2158.jpg

Dabei seit: 11.12.2001
Beiträge: 2.282
Herkunft: /dev/stderr

      Zum Anfang der Seite springen

Zitat:
Original von phlox81
Gerade bei einer solchen Einleseoperation, sollte der Unterschied nicht allzu groß sein.


Gerade dabei ist Java langsam. Jedes eingelesene Ascii-Zeichen muss erst zweimal konvertiert werden. Einmal nach Big Endian und dann nach UTF-8 (oder umgekehrt, keine Ahnung).
Dazu kommt in dem Fall, dass mehr als nur ein paar kilobyte Speicher allokiert werden muessen, was auch unwahrscheinlich viel Zeit kostet unter Java. Wenn haeufig oder wenn viel Speicher allokiert werden muss, ist Java immer noch um einen Faktor 100 bis 1000 langsamer als vergleichbare C/C++ Programme.

Ich habe mal ein kleines c++ Programm geschrieben, dass das gleiche macht.

code:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>

std::stringstream buffer;               //!< string buffer (line by line)
std::vector<char> binBuffer;            //!< binary buffer

/*!
 * Line-by-line read -- adding to stringbuffer
 */
void bufferedReader( char* fileName )
{
        std::ifstream file( fileName );
        std::string line;
        while ( ! file.eof() )
        {
                std::getline( file, line );
                buffer << line << std::endl;
        }
        file.close();
}

/*!
 * Binary-at-once read -- adding to STL vector
 */
void binReader( char* fileName )
{
        std::ifstream binFile( fileName, std::ios::binary | std::ios::in );

        binFile.seekg( 0, std::ios::end );
        size_t binSize = binFile.tellg();
        binFile.seekg( 0, std::ios::beg );

        size_t buffPos = binBuffer.size();
        binBuffer.resize( buffPos + binSize );

        binFile.read( &(binBuffer[buffPos]), binSize );

        binFile.close();
}

/*!
 * argv[1] -> filename; argv[2] -> "1": stringstream, "2": binary STL vec
 */
int main( int, char** argv )
{
        if ( std::string( argv[2] ) == "1" )
        {
                for ( int i = 0; i < 100; ++i )
                {
                        bufferedReader( argv[1] );
                }
                std::cout << "[MAIN] total bytes added to buffer: " << buffer.str().length() << std::endl;
        }
        else if ( std::string( argv[2] ) == "2" )
        {
                for ( int i = 0; i < 100; ++i )
                {
                        binReader( argv[1] );
                }
                std::cout << "[MAIN] total bytes added to buffer: " << binBuffer.size() << std::endl;
        }

        return 0;
}

Wie man sieht, muss ich die Einleseoperationen wenigsten 100 mal ausfuehren, damit ich sinnvoll eine Zeit messen kann.
Die einzulesende Datei ist der Quellcode eines Gittergenerators, die groesste Textdatei, die ich gerade finden konnte:
code:
1:
2:
$ wc ~/NLD/src/libnldtools/extern/tetgenio/tetgen.cxx
  34961  151648 1278017 /home/ulli/NLD/src/libnldtools/extern/tetgenio/tetgen.cxx
Das heisst es werden insgesammt 127801700byte in den Puffer geladen, ohne dass er zwischendurch geleert wird.
Ausserdem habe ich das Programm mit "-O0" kompiliert, damit der Kompiler nicht optimiert und der Code wirklich so ausgefuehrt wird.

Hier die Ergebnisse:
String buffer:
code:
1:
2:
3:
4:
5:
6:
$ time ./readfile /home/ulli/NLD/src/libnldtools/extern/tetgenio/tetgen.cxx 1
[MAIN] total bytes added to buffer: 127801800

real    0m9.885s
user    0m6.060s
sys     0m1.728s
STL vector / binaer:
code:
1:
2:
3:
4:
5:
6:
$ time ./readfile /home/ulli/NLD/src/libnldtools/extern/tetgenio/tetgen.cxx 2
[MAIN] total bytes added to buffer: 127801700

real    0m5.802s
user    0m1.803s
sys     0m1.812s
Und das auf einem 800MHz Duron mit 256MB Arbeistspeicher, womit die einzuladenen ~120MB schon weh tun.

Aus eigener Erfahrung weiss ich, dass das unter Java vollkommen anders aussaehe.
Ich habe es jetzt nicht ausprobiert, aber Antiheld hat ja schon bemerkt, dass eine einzige Einleseoperation so lange dauert, wie bei mir 100.

Das soll jetzt auch nicht als Aufruf oder Beitrag zum Flamewar verstanden werden, sondern ist nur eine simple Feststellung.
Wir hatten Antiheld ja bereits geholfen, und zum rumspielen und lernen ist Java ja auch ganz in Ordnung.

__________________
vescere bracis meis

29.03.2008 12:46 Black Star ist offline E-Mail an Black Star senden Homepage von Black Star Beiträge von Black Star suchen
phlox81 phlox81 ist männlich
Bote des Lichts und Moderator


images/avatars/avatar-2264.jpg

Dabei seit: 19.10.2002
Beiträge: 3.028
Herkunft: Irgendwo im Nirgendwo

      Zum Anfang der Seite springen

Zitat:
Original von Black Star
Zitat:
Original von phlox81
Gerade bei einer solchen Einleseoperation, sollte der Unterschied nicht allzu groß sein.


Gerade dabei ist Java langsam. Jedes eingelesene Ascii-Zeichen muss erst zweimal konvertiert werden. Einmal nach Big Endian und dann nach UTF-8 (oder umgekehrt, keine Ahnung).
Dazu kommt in dem Fall, dass mehr als nur ein paar kilobyte Speicher allokiert werden muessen, was auch unwahrscheinlich viel Zeit kostet unter Java. Wenn haeufig oder wenn viel Speicher allokiert werden muss, ist Java immer noch um einen Faktor 100 bis 1000 langsamer als vergleichbare C/C++ Programme.



Gerade hier solltest du einen modernen GC nicht unterschätzen. Aber natürlich ist C++ hier immer etwas schneller, da es das ja direkt machen kann.
Trotzdem sollte man nicht den Fehler begehen, und als C++ Programmierer versuchen ein entsprechendes Java Programm gleich gut implementieren (in Java!) zu wollen.
Dafür fehlt einem einfach das Hintergrundwissen häufig. Zu mal man auch Java noch optimieren kann.

phlox

__________________
Intelligenz ist eine Illusion des Menschen

phlox81.de | codenode.de
29.03.2008 14:35 phlox81 ist offline E-Mail an phlox81 senden Homepage von phlox81 Beiträge von phlox81 suchen
PygoscelisPapua PygoscelisPapua ist männlich
BlackBoarder


images/avatars/avatar-2293.png

Dabei seit: 20.12.2003
Beiträge: 1.309
Herkunft: Kiel, Schleswig-Holstein, Germany

      Zum Anfang der Seite springen

Wie ich oben schon mal geschrieben habe, ist das, wie wenn man Äpfel mit Birnen vergleicht.

Schreib doch mal ein Applett oder ein Servlett in C++. Schreib doch mal ein Programm in C++, dass Hardware- und Betriebssystemunabhängig auf allen Rechnern, ja sogar auf Handy, PDAs, MDAs, Toastern oder Mikrowellen läuft.

Wenn das C++ genau so wie Java hinbekommt - dann können wir uns darüber unterhalten, ob C++ besser als Java ist, oder nicht, weil es Performanter ist, etc.

Solange das nicht der Fall ist, kann man mit Deiner Argumentation vielleicht jemanden eine Freude machen, der einen Windowstreiber in Java schreiben möchte -- der hat dann aber auch keine Ahnung über die Einsatzswecke von Java und C und C++.
Keine Freude machst Du damit allerdings Leuten, die mit Java ein Programm schreiben wollen, und dieses in Java performanter machen wollen (denn in der Regel ist dann ja auch davon aus zu gehen, dass diese Leute wissen, warum sie Java einsezten - und zumindest bei Antiheld nehme ich das auch an)...

__________________
There are only two kinds of programming languages: those people always bitch about and those nobody uses.
(Bjarne Stroustrup)
*
Moving on to pastures new
GPG Key

29.03.2008 15:11 PygoscelisPapua ist offline Homepage von PygoscelisPapua Beiträge von PygoscelisPapua suchen
phlox81 phlox81 ist männlich
Bote des Lichts und Moderator


images/avatars/avatar-2264.jpg

Dabei seit: 19.10.2002
Beiträge: 3.028
Herkunft: Irgendwo im Nirgendwo

      Zum Anfang der Seite springen

Zitat:
Original von PygoscelisPapua
Wie ich oben schon mal geschrieben habe, ist das, wie wenn man Äpfel mit Birnen vergleicht.

Schreib doch mal ein Applett oder ein Servlett in C++. Schreib doch mal ein Programm in C++, dass Hardware- und Betriebssystemunabhängig auf allen Rechnern, ja sogar auf Handy, PDAs, MDAs, Toastern oder Mikrowellen läuft.

Sowas ließe sich durchaus auch in C++ um setzen, es gibt sogar kleinere nicht so bekannte AppServer für C++. Z.B. tntnet.

Und noch etwas: C++ ist keine einheitliche Plattform, wie es Java vorgibt zu sein.
Java braucht immer seine Laufzeitumgebung, welche selber nicht in Java implementiert ist.

http://bash.org/?338364

Zitat:

Wenn das C++ genau so wie Java hinbekommt - dann können wir uns darüber unterhalten, ob C++ besser als Java ist, oder nicht, weil es Performanter ist, etc.


Ich mag diese Java vs. C++ vs. .net Flames nicht. Ignorieren sie doch völlig, das sie aus einer Zeit stammen in der der Softwaremarkt noch die Größe eines Fischteiches hatte. Mittlerweile ist aber daraus ein riesen Ozean geworden, und da ist nun mal platz für Vielfalt, weshalb es auch in Zukunft eher mehr als weniger Programmiersprachen geben wird.

Und wann gibts eigentlich mal ne ISO Norm für Java? großes Grinsen

phlox

__________________
Intelligenz ist eine Illusion des Menschen

phlox81.de | codenode.de
29.03.2008 15:20 phlox81 ist offline E-Mail an phlox81 senden Homepage von phlox81 Beiträge von phlox81 suchen
Baumstruktur | Brettstruktur
Gehe zu:
Neues Thema erstellen Antwort erstellen
BlackBoard » Design, Programmierung & Entwicklung » Programmieren » Java Datei Einlesen, performant?

Forensoftware: Burning Board 2.3.6, entwickelt von WoltLab GmbH