Parser: Datei auslesen, Datei erstellen - Geschwindigkeit

Status
Nicht offen für weitere Antworten.

redbomber

Bekanntes Mitglied
Hi zusammen, ich habe mal eine Frage:

Mein Parser liest Daten aus einer Datei und speichert diese in verschiedenen Datentypen:

Code:
private static LinkedList<String> probeNames = new LinkedList<String>();
private static LinkedList<LinkedList<Double>> allProbeValues= new LinkedList<LinkedList<Double>>();
private static LinkedList<String> chrome = new LinkedList<String>();
private static LinkedList<Double> positions = new LinkedList<Double>();
private static LinkedList<Integer> strand = new LinkedList<Integer>();

Danach schreibe ich die ganzen Daten wieder in eine neue Datei (ich brauch einfach eine spezielle Formatierung)


Das File das ich auslese ist sehr gross (Tabulatorgetrennte Werte etwa 120 MB).

Nun das was mich verwundert:
Das Auslesen der Datei geht sogar noch recht schnell (1-2 Minuten vielleicht).
Aber dann die neue Datei erstellen (wieder eine tabulatorgetrennte Datei) ... da warte ich eeewig. Alle paar Minuten schafft der vielleicht 10.000 Zeilen
(sind insgesamt 120.000 Zeilen).

Woran liegt das? Mache ich irgendwo einen Fehler? Gibt es Unterschiede wie man Daten in ein File schreibt?
Oder dauert das schreiben einfach länger?
 
Schreiben soll schon länger dauern als lesen, aber nicht mehr als 5-10 Min,
(ohne Tests mal eben vermutet),

wenn das Parsen aufwendig ist gegenüber Formatieren zur Datei hin (Strings oder Bytes?), dann kann das Schreiben sogar schneller sein als das Lesen

ohne Code kann man über die Gründe nur raten, zwei Tipps:
1. sparsam Strings zusammensetzten, nicht ständig a = b +c
2. BufferedWriter benutzen, nicht jedes Byte einzeln auf die Festplatte schreiben, sondern nur große Blöcke
 
also das dauert bei mir deutlich länger als 5-10 Minuten mehr.


Hier mal mein Code:

Code:
public static void createFile(int experimentNumber) {

		System.out.println("Creating file");
		try {
			String nameOfAnalysisFile = "C:\\Data\\datafile.csv";
			File analysisDataFile = new File(nameOfAnalysisFile);
			analysisDataFile.createNewFile();
			BufferedWriter buffWriter = new BufferedWriter(new FileWriter(
					analysisDataFile));

			// Write comment lines
			buffWriter.write("Id"+"\t");
			for(int i = 1; i <= eNumber; i++){
				buffWriter.write(i + "\t");
			}
			buffWriter.write("Info"+"\n");			
			
			
			// write other lines
			int probeCounter = 0;
			for(String probeName: probeNames){
				// write probe name and experiment values
				buffWriter.write(probeName+"\t");
				LinkedList<Double> values = allProbeValues.get(probeCounter);
					
				for(Double val : values){
					buffWriter.write(val + "\t");
				}
				
				// write lociInfo
				String chromeName = chrome.get(probeCounter);
				Double position = positions.get(probeCounter);
				Integer strandName = strand.get(probeCounter);
				if(strandName == 0){
					buffWriter.write("\"species> " + chromeName + ":" + position.intValue() + "-" + (position.intValue() + 25) +":" + "+\"" + "\n");
				} else if(strandName == 1){
					buffWriter.write("\"species> " + chromeName + ":" + position.intValue() + "-" + (position.intValue() + 25) + ":" + "-\"" + "\n");
				} else {
					System.err.println("Error: strand is neither plus nor minus");
				}

				probeCounter++;
			}
			
			buffWriter.close();

		} catch (Exception e) {
			e.printStackTrace();
		}
	}
 
Wie gesagt: nio ist wesentlich schneller bei großen Daten, das wird also den größten Unterschied machen.
Wenn du aus irgendeinem Grund kein nio verwenden möchtest, dann vermeide zB solche Dinge:
buffWriter.write(probeName+"\t");
zweimal write ist effizienter als erst zwei String zusammen zu setzen und sie dann zu schreiben
 
bei LinkedList ist es nicht besonders effizient, mit get(index) zuzugreifen,
da muss jedes Mal ganz vorne angefangen und dann die Link-Kette durchlaufen werden,

kann mir vorstellen, dass das bei 120.000 allein schon ne Weile dauert,

such dir testweise einmalig eine feste Menge von Testdaten raus und schreibe die 120.000x hintereinander

für die richtigen Daten verwende dann Iterator,
4 Iterator gleichzeitig zu durchlaufen ist allerdings unschön,

wenn die Daten alle gut zusammenpassen, dann verwende nur EINE LinkedList<MyDataObject>, in MyDataObject sind Name, Double-List usw alles enthalten,
bei nur einer Liste brauchst du dann auch gar keinen Iterator, sondern alternativ eine for-each-Schleife wie du sie derzeit für probeName schon verwendest

---

allein um den Unterschied zu testen, kannst du bei der
> buffWriter.write("Info"+"\n");
Frage auch einfach mal das \n weglassen
 
Zeile 24 ist wahrscheinlich das schlimmste... Wahlfreier Zugriff auf eine LinkedList. Wandele vorher die LinkedList in eine ArrayList um. Dann wirst Du wahrscheinlich den größten Brocken erledigt haben. Darüber hinaus hat Wildcard natürlich auch noch recht.

[ edit ] Slater, wir sollten uns absprechen. 🙂 Landei auch noch. :lol:
 
Code:
LinkedList<Double> values = allProbeValues.get(probeCounter);
Per Index auf LinkedList zuzugreifen ist auch nicht das Wahre, falls selbige etwas größer ist. Teste mal, ob ArrayList da schneller ist, oder nimm Iteratoren.
 
Das sollte schonmal ein paar Punkte in Sachen Geschwindigkeit bringen.
Code:
public static void createFile(int eNumber) {

      System.out.println("Creating file");
      try {
         String nameOfAnalysisFile = "datafile.csv";
         File analysisDataFile = new File(nameOfAnalysisFile);
         analysisDataFile.createNewFile();
         
         StringBuilder sb = new StringBuilder();
         BufferedWriter buffWriter = new BufferedWriter(new FileWriter(
               analysisDataFile));

         // Write comment lines
         sb.append("Id");
         sb.append("\t");
         for(int i = 1; i <= eNumber; i++){
            sb.append(i);
            sb.append("\t");
         }
         sb.append("Info");
         sb.append("\n");         
         buffWriter.write(sb.toString());
         sb.setLength(0);
         
         // write other lines
         int probeCounter = 0;
         for(String probeName: probeNames){
            // write probe name and experiment values
            buffWriter.write(probeName+"\t");
            LinkedList<Double> values = allProbeValues.get(probeCounter);
               
            for(Double val : values){
               sb.append(val);
               sb.append("\t");
            }
            
            // write lociInfo
            String chromeName = chrome.get(probeCounter);
            Double position = positions.get(probeCounter);
            Integer strandName = strand.get(probeCounter);
            if(strandName == 0){
               sb.append("\"species> ");
               sb.append(chromeName);
               sb.append(":");
               sb.append(position.intValue());
               sb.append("-");
               sb.append(position.intValue() + 25);
               sb.append(":");
               sb.append("+\"");
               sb.append("\n");
            } else if(strandName == 1){
              sb.append("\"species> ");
               sb.append(chromeName);
               sb.append(":");
               sb.append(position.intValue());
               sb.append("-");
               sb.append(position.intValue() + 25);
               sb.append(":");
               sb.append("-\"");
               sb.append("\n");
            } else {
               System.err.println("Error: strand is neither plus nor minus");
            }

            buffWriter.write(sb.toString());
            sb.setLength(0);
            
            probeCounter++;
         }
         
         buffWriter.close();

      } catch (Exception e) {
         e.printStackTrace();
      }
   }
 
Sorry Ebenius,
ja wie so oft hast du mich auch schon darauf hingewiesen 🙁

Ich habe jetzt alle LinkedList, auf denen Indexzugriff stattfinden.
Ebenso vermeide ich das zusammensetzen von Strings
und teste gerade das Ergebnis.

Vielen Dank euch allen.


@ didjitalist

Ne eigentlich kann ich von der Datei eine Zeile einlesen
und dann gleich die Zeile umformatiert in die neue Datei ausgeben... stimmt, da könnte ich mir das ganze Durchlaufen der Listen sparen.
Ich dachte zuerst dass ich alle Daten brauche, da ich in jeder zeile eine Wert berechnen muss, dies brauch ich scheins aber doch nicht.
 
Status
Nicht offen für weitere Antworten.

Zurück
Oben