Input/Output Programm zum Auslesen/Beschreiben von Textdateien, wie Geschwindigkeit erhöhen?

BobDer

Mitglied
Guten Abend,
das Thema ist gewiss sehr speziell, aber vielleicht kann mir hier trotzdem geholfen werden.
Ich habe eine Textdatei, in der mehrere Hunderttausend binär codierte Werte mit einer Länge von je 4-9 Byte stehen. Diese möchte ich auslesen und in Abhängigkeit eines Wertes in eine von Acht Zieldateien schreiben.

Ein Grundprogramm mit der Funktionalität steht unten. Das Problem bei meinem Programm ist die lange Laufzeit. Je nach Umfang der Quelldatei schafft das Programm 5.000-6.000 Werte / Sekunde.

Leider konnte ich nicht genau lokalisieren, was genau so viel Zeit verbrät.
Vielleicht kann ja mal jemand einen Blick auf den Code werfen und mir Tipps zum Beschleunigen dse Vorgangs geben. Wäre echt super. :)

Main:
Java:
long startTime = System.currentTimeMillis();
int indexNumber[] = new int[8];
 
  try(FileInputStream fis = new FileInputStream(fileName);){
          int tempValue=0;
          int lastCode[] = {-1,-1,-1,-1,-1,-1,-1,-1};
         
         while(fis.available()>0){
              int tempCode=0;
              int tempChannel=0;
              int dataFragment=0;
              tempValue=fis.read();
              tempCode = tempValue>>6;
              tempChannel = (tempValue&0b00111100)>>2;
              dataFragment = (tempValue&0b00000011);
              array1[tempChannel][tempCode].setChannel(tempChannel);
              try(BufferedWriter bwriter = new BufferedWriter(new FileWriter(targetPath+"/Sensor"+tempChannel+".txt",true))){

              if(tempCode==0){ // Code 0
                  extractCode0(array1[tempChannel][0], fis, dataFragment);
                  indexNumber[tempChannel]++;
                  lastCode[tempChannel]=0;
                  bwriter.write(formatOutput(indexNumber[tempChannel], tempCode, tempChannel, array1[tempChannel][tempCode]));
                  bwriter.newLine();
              } else if (tempCode==1){ // Code 1
                  extractCode1(array1[tempChannel][1], fis, dataFragment);
                  completeDataCode1(array1[tempChannel][0], array1[tempChannel][1]);
                  indexNumber[tempChannel]++;
                  lastCode[tempChannel]=1;
                  bwriter.write(formatOutput(indexNumber[tempChannel], tempCode, tempChannel, array1[tempChannel][tempCode]));
                  bwriter.newLine();
              } else if (tempCode==2){ // Code 2
                  extractCode2(array1[tempChannel][2], fis, dataFragment);
                  indexNumber[tempChannel]++;
                  if(lastCode[tempChannel]==1){
                      completeDataCode2(array1[tempChannel][1], array1[tempChannel][2]);
                  } else if (lastCode[tempChannel]==0){
                      completeDataCode2(array1[tempChannel][0], array1[tempChannel][2]);
                  }
                  bwriter.write(formatOutput(indexNumber[tempChannel], tempCode, tempChannel, array1[tempChannel][tempCode]));
                  bwriter.newLine();
              }
              } catch (IOException e5){
                  System.err.println("Couldn't write to targetfiles.");
                  e5.printStackTrace();
              }
      
          }

  } catch (IOException   e4){
      System.err.println("Couldn't read sourcefile.");
      e4.printStackTrace();
  };
 
  long endTime = System.currentTimeMillis();
  int totalReading=0;
  for(int i=0;i<indexNumber.length;i++){
      totalReading+=indexNumber[i];
  }
  long elapsedTime = endTime-startTime;
  System.out.println("Read "+totalReading+" values in "+elapsedTime+ " Milliseconds.");

Funktionen unter der Main:
Java:
static void extractCode0(Messwert messwert, FileInputStream fis, int dataFragment) throws IOException{
        int valueArray[] = new int[8];
        int frequenz=0;
        switch(dataFragment){
            case 0:
                frequenz=1;
                break;
            case 1:
                frequenz=10;
                break;
            case 2:
                frequenz=100;
                break;
            case 3:
                frequenz=1000;
                break;
        }
        messwert.setFreq(frequenz);
       
        for(int i=0;i<valueArray.length;i++){
            valueArray[i]=fis.read();
        }
       
        int day = valueArray[0]>>3;
        messwert.setDay(day);
       
        int month = ((valueArray[0]&0b00000111)<<1)|(valueArray[1]>>7);
        messwert.setMonth(month);
       
        int year = valueArray[1]&0b01111111;
        messwert.setYear(year);
       
        int hour = valueArray[2]>>3;
        messwert.setHour(hour);
       
        int minute = ((valueArray[2]&0b00000111)<<3)|(valueArray[3]>>5);
        messwert.setMinute(minute);
       
        int second = ((valueArray[3]&0b00011111)<<1)|(valueArray[4]>>7);
        messwert.setSecond(second);
       
        int millisecond = ((valueArray[4]&0b01111111)<<3)|(valueArray[5]>>5);
        messwert.setMillisecond(millisecond);
       
        int measurement = ((valueArray[5]&0b00011111)<<10)|(valueArray[6]<<2)|(valueArray[7]>>6);

        messwert.setMesswert(measurement/1000.0);
    }

Java:
static void extractCode1(Messwert messwert, FileInputStream fis, int dataFragment) throws IOException{
       
        
        int valueArray[] = new int[4];
       
        for(int i=0;i<valueArray.length;i++){
            valueArray[i]=fis.read();
        }
       
        int second = dataFragment<<4|(valueArray[0]>>4);
        messwert.setSecond(second);
       
        int millisecond = ((valueArray[0]&0b00001111)<<6)|(valueArray[1]>>2);
        messwert.setMillisecond(millisecond);
       
        int measurement = ((valueArray[1]&0b00000011)<<13)|(valueArray[2]<<5)|(valueArray[3]>>3);

        messwert.setMesswert(measurement/1000.0);
       
    }
Java:
  static void extractCode2(Messwert messwert, FileInputStream fis, int dataFragment) throws IOException{
       

        int valueArray[] = new int[3];
     
        for(int i=0;i<valueArray.length;i++){
            valueArray[i]=fis.read();
        }
               
        int millisecond = dataFragment<<8|valueArray[0];
        messwert.setMillisecond(millisecond);
       
        int measurement = (valueArray[1]<<7)|(valueArray[2]>>1);
       
        messwert.setMesswert(measurement/1000.0);
       
    }
Java:
  static void completeDataCode1(Messwert dataSource, Messwert dataSink){
        dataSink.setFreq(dataSource.getFreq());
        dataSink.setDay(dataSource.getDay());
        dataSink.setMonth(dataSource.getMonth());
        dataSink.setYear(dataSource.getYear());
        dataSink.setHour(dataSource.getHour());
        dataSink.setMinute(dataSource.getMinute());
    }
Java:
static void completeDataCode2(Messwert dataSource, Messwert dataSink){
        dataSink.setFreq(dataSource.getFreq());
        dataSink.setDay(dataSource.getDay());
        dataSink.setMonth(dataSource.getMonth());
        dataSink.setYear(dataSource.getYear());
        dataSink.setHour(dataSource.getHour());
        dataSink.setMinute(dataSource.getMinute());
        dataSink.setSecond(dataSource.getSecond());
    }
Java:
static String formatOutput(int index, int code, int channel, Messwert data){
       
        char unit;
        if(channel<7){
            unit = 'V';
        } else {
            unit = 'A';
        }
        // Format: index Code Channel Freq DD.MM.YY HH:MM:SS.ms Value
        String format = "%d. C%d Kanal %d %dHz %02d.%02d.%02d %02d:%02d:%02d.%03d %.3f%c";                     
        String output = String.format(format, index, code, channel,data.getFreq(),data.getDay(),data.getMonth(),data.getYear(),data.getHour(),data.getMinute(),data.getSecond(),data.getMillisecond(),data.getMesswert(),unit);
        return output;

    }
 

BobDer

Mitglied
Danke für die Antwort.
Ich bin eher ein Anfänger. Als IDE benutze ich Eclipse 4.5.1.

Einen Profiler habe ich noch nie beutzt. Ich werde mal gucken was das ist und wie man es benutzt.

Ich habe spontan keinen vernünftigen Weg gefunden, wie man den Writer sonst dynamisch auf die entsprechende Datei setzen kann. Alternativ könnte man vor der Schleife ein halbes Dutzend Writer auf einmal öffnen und dann in der Schleife auf den entsprechenden Writer zu der gewünschten Datei zugreifen.
 

Thallius

Top Contributor
Also ich würde die Werte erstmal auslesen und in 8 Strings speichern und dann wenn die String erstellt sind mit einem mal schreiben.

Gruß

Claus
 

thet1983

Top Contributor
ich würde switch verwenden

if(tempCode==0){ // Code 0
extractCode0(array1[tempChannel][0], fis, dataFragment);
indexNumber[tempChannel]++;
lastCode[tempChannel]=0;
bwriter.write(formatOutput(indexNumber[tempChannel], tempCode, tempChannel, array1[tempChannel][tempCode]));
bwriter.newLine();
} else if (tempCode==1){ // Code 1
extractCode1(array1[tempChannel][1], fis, dataFragment);
completeDataCode1(array1[tempChannel][0], array1[tempChannel][1]);
indexNumber[tempChannel]++;
lastCode[tempChannel]=1;
bwriter.write(formatOutput(indexNumber[tempChannel], tempCode, tempChannel, array1[tempChannel][tempCode]));
bwriter.newLine();
} else if (tempCode==2){ // Code 2
extractCode2(array1[tempChannel][2], fis, dataFragment);
indexNumber[tempChannel]++;
if(lastCode[tempChannel]==1){
completeDataCode2(array1[tempChannel][1], array1[tempChannel][2]);
} else if (lastCode[tempChannel]==0){
completeDataCode2(array1[tempChannel][0], array1[tempChannel][2]);
}
bwriter.write(formatOutput(indexNumber[tempChannel], tempCode, tempChannel, array1[tempChannel][tempCode]));
bwriter.newLine();
}
 

thet1983

Top Contributor
weil es schneller ist...

Jetzt wirst du sagen: wer sagt das? Dann werde ich sagen: weil switch nunmal schneller ist..und ich es schon 1-2-3-viele schon bei solchen Zwecken verwendet habe. (Excel)
Dann wirst du sagen: wo steht das?
Dann werde ich sagen: ich bin dann mal weg! Schönes Wochenende an den TE

;)
 

mrBrown

Super-Moderator
Mitarbeiter
weil es schneller ist...

Jetzt wirst du sagen: wer sagt das? Dann werde ich sagen: weil switch nunmal schneller ist..und ich es schon 1-2-3-viele schon bei solchen Zwecken verwendet habe. (Excel)
Dann wirst du sagen: wo steht das?
Dann werde ich sagen: ich bin dann mal weg! Schönes Wochenende an den TE

;)

Eine Empfehlung zu Performance geben und die nicht mal begründen können ist immer super...
Vor allem wenn das eine absolute Micro-Optimization ist, die, selbst wenn es Unterschiede zwischen den beiden geben würde, auf die Gesamt-Performance nur minimalste Auswirkungen hätte...


In diesem Fall führt beides zu annähernd dem gleichen Assembler-Code (der eine hat ein je, der andere ein jne), dürfte deshalb sogar eher pro-if ausgehen, weil's damit seltener zum Sprung kommt. Aber selbst das dürfte mit Branch-Prediction völlig irrelevant sein...
 

BobDer

Mitglied
Guten Abend,
ich habe das Programm jetzt mit "JProfiler" ein wenig unter die Lupe genommen.

Den größten Einfluss hatte der ständige Wechsel des BufferedWriter innerhalb der Schleife.
Daher habe ich jetzt vor der Schleife ein Array mit Writern angelegt, die auf die entsprechende Ausgangsdatei zeigen und in der Schleife nur ausgewählt werden.
Java:
BufferedWriter bwriterA[] = new BufferedWriter[8];
          try{
              for(int i=0;i<bwriterA.length;i++){
                  bwriterA[i]=new BufferedWriter(new FileWriter(targetPath+"/Sensor"+(i+1)+".txt"));
              }

           // Wie im ersten Beitrag

           }catch(IOException e5){
              for(int i=0;i<bwriterA.length;i++){
                  bwriterA[i].close();
              }
              System.err.println("Couldn't write to targetfiles.");
              e5.printStackTrace();
          } finally {
              for(int i=0;i<bwriterA.length;i++){
                  bwriterA[i].close();
              }
          }
Dafür bin ich wieder auf try{}catch{}finally{} umgestiegen, da man in dem try() mit auto-close wohl kein Array anlegen kann. Zumindest habe ich es nicht hinbekommen.

Alleine dadurch ist die Laufzeit (gemessen über die Systemzeit) bei 2,3 Millionen Datensätzen von ca. 388 Sekunden auf 60,5 Sekunden gesunken.
Ein weiterer Zeitfresser war String.format in formatOutput.
Damit hat sich zwar jetzt die Formatierung von
1. C0 Kanal 1 1000Hz 22.03.18 20:39:50.051 0,439V nach
1. C0 Kanal 1 1000Hz 22.3.18 20:39:50.51 0.439V ein wenig geändert, dafür ist die Zeit auf knapp über 30 Sekunden gesunken.
Einziger Nachteil ist jetzt die Darstellung von "00" Werten, die nur noch als "0" dargestellt werden. Gibt es da eine gute Alternative zum Stringformat, um vorstehende Nullen darzustellen?

Die Laufzeit teilt sich jetzt so auf:
performance4.JPG
Die 10.523 ms in java.io.FileInputStream.available, ist das die Zeit, die das Programm nur in der while(fis.available()>0)-Schleife, aber außerhalb von den anderen Funktionen verbringt?
Java:
while(fis.available()>0){
             
              int tempCode=0;
              int tempChannel=0;
              int dataFragment=0;
             
              tempValue=fis.read();
             
              tempCode = tempValue>>6;
              tempChannel = ((tempValue&0b00111100)>>2)-1;
              dataFragment = (tempValue&0b00000011);
             
              array1[tempChannel][tempCode].setChannel(tempChannel);
              if(tempCode==0){ // Code 0
                  extractCode0(array1[tempChannel][0], fis, dataFragment);
                  indexNumber[tempChannel]++;
                  lastCode[tempChannel]=0;
                  bwriterA[tempChannel].write(formatOutput(indexNumber[tempChannel], tempCode, tempChannel, array1[tempChannel][tempCode]));
                  bwriterA[tempChannel].newLine();

              } else if (tempCode==1){ // Code 1
                  extractCode1(array1[tempChannel][1], fis, dataFragment);
                  completeDataCode1(array1[tempChannel][0], array1[tempChannel][1]);
                  indexNumber[tempChannel]++;
                  lastCode[tempChannel]=1;
                  bwriterA[tempChannel].write(formatOutput(indexNumber[tempChannel], tempCode, tempChannel, array1[tempChannel][tempCode]));
                  bwriterA[tempChannel].newLine();
                 
              } else if (tempCode==2){ // Code 2
                  extractCode2(array1[tempChannel][2], fis, dataFragment);
                  indexNumber[tempChannel]++;
                  if(lastCode[tempChannel]==1){
                      completeDataCode2(array1[tempChannel][1], array1[tempChannel][2]);
                  } else if (lastCode[tempChannel]==0){
                      completeDataCode2(array1[tempChannel][0], array1[tempChannel][2]);
                  }
                  bwriterA[tempChannel].write(formatOutput(indexNumber[tempChannel], tempCode, tempChannel, array1[tempChannel][tempCode]));
                  bwriterA[tempChannel].newLine();
              }
          }
 

mrBrown

Super-Moderator
Mitarbeiter
Dafür bin ich wieder auf try{}catch{}finally{} umgestiegen, da man in dem try() mit auto-close wohl kein Array anlegen kann. Zumindest habe ich es nicht hinbekommen.
try-with-resources funktioniert nicht mit Arrays. Wenn man da so was dynamisches will, muss man ein bisschen basteln und kann damit das schließen zumindest etwas "verstecken"

Ein weiterer Zeitfresser war String.format in formatOutput.
Damit hat sich zwar jetzt die Formatierung von
1. C0 Kanal 1 1000Hz 22.03.18 20:39:50.051 0,439V nach
1. C0 Kanal 1 1000Hz 22.3.18 20:39:50.51 0.439V ein wenig geändert, dafür ist die Zeit auf knapp über 30 Sekunden gesunken.
Einziger Nachteil ist jetzt die Darstellung von "00" Werten, die nur noch als "0" dargestellt werden. Gibt es da eine gute Alternative zum Stringformat, um vorstehende Nullen darzustellen?
Wie sieht der Code dazu aus?
Möglicherweise reicht schon sowas in der Art von x<100 ? "0"+x : x


Die 10.523 ms in java.io.FileInputStream.available, ist das die Zeit, die das Programm nur in der while(fis.available()>0)-Schleife, aber außerhalb von den anderen Funktionen verbringt?
Die es nur in fis.available() verbringt - darauf hast du aber nicht wirklich Einfluss.

uU kann man das verbessern, indem man die Datei in einem Rutsch einliest und danach mit einem byte-Array arbeitet, oder aber das ganze in einen BufferedInputStream wrappt. Ich weiß allerdings nicht, wie groß die Auswirkungen in diesem Fall sind
 
Zuletzt bearbeitet:

DrZoidberg

Top Contributor
Du liest jedes Byte einzeln ein. Das ist sehr langsam. Versuch statt dessen eine grössere Anzahl an Bytes gleichzeitig in ein Array zu lesen, z.B. 1 Million. Die Methode FileInputStream.read(byte[] array) liefert die Anzahl der gelesenen Bytes zurück. Wenn das Ende der Datei erreicht ist, wird -1 zurückgeliefert. Die available() Methode brauchst du dann also gar nicht mehr.
 

BobDer

Mitglied
So, ich habe jetzt noch ein wenig rumprobiert.
Durch den Wechsel von einem FileInputStream zu einem BufferedInputStream ist die Zeit von ca. 33 Sekunden auf ca. 11 Sekunden gesunken.

Danach habe ich versucht einen FileInputStream mit read(byte[] bytearray) zu erstellen.
Das hat am Ende auch geklappt, allerdings war das Resultat ernüchternd. Je nach Buffergröße lag die Zeit bei ca. 10-11 Sekunden, Zeitersparnis ist bei meiner Implementierung nahezu nicht existent.

Implementierung:

Java:
package hauptpaket;

import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.IOException;

public class Fileaccess {
    private  byte bytebuffer[] = new byte[8192];
    private  int position=0;
    private  int remainderCount=0;
    private  FileInputStream fisObject;

   public  void reset(){
       this.position=0;
    }
public  int getRemainderData(){
        return this.remainderCount;
    }

public  void linkFIS(FileInputStream fisObjectIn){
        this.fisObject=fisObjectIn;
    }

public  int read(){
        int value=-1;
        if(this.position<this.bytebuffer.length){
            value=this.bytebuffer[this.position]&0xff;
            this.position++;
            if(this.remainderCount>0){
                this.remainderCount--;
            }
        }
        return value;
    }


public int readData() throws IOException{
        int value=-1;
       
        if(this.remainderCount==0){   
            this.remainderCount=fisObject.read(bytebuffer);
            reset();
        }
        value=read();
        return value;
    }


Als kleines rudimentäres "Experiment" hatte ich dann noch BufferedInputStream mit einem ByteArrayInputStream verglichen.
Java:
System.out.println("Test BufferedInputStream:");
        long testTime1 = System.currentTimeMillis();
        try(BufferedInputStream bis1 = new BufferedInputStream(new FileInputStream("test.txt"));){
byte bytebuffer1[] = new byte[bis1.available()];
int index=0;
while(bis1.available()>0){
                bytebuffer1[index]=(byte)bis1.read();
                index++;
            }

try(BufferedWriter bwriter1 = new BufferedWriter(new FileWriter("testout1.txt"))){
char c;
               
                for(byte b:bytebuffer1){
                    c = (char)b;
                    bwriter1.write(c);
                   
                }
                }catch(IOException e8){
                   
                }
} catch(IOException e7){
            System.err.println("Fehler");
        }
long testTime2 = System.currentTimeMillis();
        System.out.println("Zeit: "+(testTime2-testTime1)+"ms");

Java:
System.out.println("Test ByteArrayInputStream:");
        byte bytebuffer[] = new byte[8192];
        try(FileInputStream fis1 = new FileInputStream("test.txt");){
int readCount=0;
char c;
            ByteArrayInputStream bais = new ByteArrayInputStream(bytebuffer);
            try(BufferedWriter bwriter1 = new BufferedWriter(new FileWriter("testout2.txt"))){
               
               
                while((readCount=fis1.read(bytebuffer))!=-1){
int baisCount=0;
int preCount=bytebuffer.length;
while((baisCount=bais.available())>(preCount-readCount)){
                       
                        bwriter1.write((char)bais.read());
                    }
                    bais.reset();
                   
                }
}catch(IOException e8){
               
            }
           
           
        } catch(IOException e7){
            System.err.println("Fehler");
        }
        long testTime3 = System.currentTimeMillis();
        System.out.println("Zeit: "+(testTime3-testTime2)+"ms");

Dabei waren in der Inputdatei einfach eine lange Zeichenfolge.
Das Überraschende:
Für die Datei mit 2.237.761 Zeichen hat der BIS ca. 5 Sekunden gebraucht.
Der BAIS war, zumindest bei dem Test oben, nach <100ms fertig.
Die beiden Outputdateien sind identisch.
Habe ich bei den Testprogrammen etwas falsch gemacht oder ist das BAIS wirklich so viel schneller? Nur *spoiler* profitiert das Hauptprogramm von diesem vermeintlichen Geschwindigkeitsvorteil nicht.

Ich hatte dann mal versucht das im Hauptprogramm umzusetzen:

Java:
package hauptpaket;

import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.IOException;

public class Fileaccess {
    private  byte bytebuffer[] = new byte[8192];
    private  int position=0;
    private  int remainderCount=0;
    private  FileInputStream fisObject;
    private ByteArrayInputStream baisObject;
  
    public  void reset(){
        baisObject.reset();
    }
   
   
   
    public  void setRemainderData(int count){
        this.remainderCount=count;
       
    }
   
    public  int getRemainderData(){
        return this.remainderCount;
    }
   
    public  void linkFIS(FileInputStream fisObjectIn){
        this.fisObject=fisObjectIn;
    }
   
    public  void createBAIS(){
        this.baisObject= new ByteArrayInputStream(this.bytebuffer);
    }
      
    public  int read(){
        int value=-1;

        if(remainderCount>0){
            value=baisObject.read()&0xff;
            if(this.remainderCount>0){
                this.remainderCount--;
            }
        }

        return value;
    }
   
    public int readData() throws IOException{
        int value=-1;
       
        if(this.remainderCount==0){
              this.remainderCount=fisObject.read(bytebuffer);
            reset();
        }
  
       
        value=read();
  
        return value;
    }
   
}
In der Main dann:
Java:
try(FileInputStream fis = new FileInputStream(fileName);){
Fileaccess saveHelp = new Fileaccess();
saveHelp.linkFIS(fis);
          saveHelp.createBAIS();
 [....]
while(fis.available()>0||saveHelp.getRemainderData()>0){
[....]
// Aufruf mit
tempValue=saveHelp.readData();
[....]

Leider liegt die Zeitersparnis in meinem Fall, gegenüber dem einfachen BufferedInputStream, bei +- 0.

Den ganzen Aufwand hätte ich mir dann wohl sparen können. ;)
Das Einlesen der Daten scheint dann wohl doch nicht (mehr) der Flaschenhals zu sein.

So fällt mir dazu aktuell aber auch nichts mehr ein, vielleicht bekomme ich das Programm in dem Anwendungsfall einfach nicht mehr schneller und werde damit leben müssen.
 

mrBrown

Super-Moderator
Mitarbeiter
Das Einlesen der Daten scheint dann wohl doch nicht (mehr) der Flaschenhals zu sein.
Das kannst du einfach mit‘m Profiler überprüfen ;)


Die beiden Programme muss ich mir mal aufm Rechner angucken, ich würde da zumindest kleine Unterschiede vermuten.
Aufm Handy stört da aber die Formatierung zu viel...
 

RalleYTN

Bekanntes Mitglied
weil es schneller ist...

Jetzt wirst du sagen: wer sagt das? Dann werde ich sagen: weil switch nunmal schneller ist..und ich es schon 1-2-3-viele schon bei solchen Zwecken verwendet habe. (Excel)
Dann wirst du sagen: wo steht das?
Dann werde ich sagen: ich bin dann mal weg! Schönes Wochenende an den TE

;)
Code:
A switch compiles into a lookup table which is fundamentally different then the if/else statements. If the last statement in a if/else chain is the one you want you have to check all the previous if/else first. This is not the case with a switch.
Code:
The power of switch is twofold:
[LIST=1]
[*]It is more descriptive
[*]It saves CPU cycles
[/LIST]
Your post already comments on the descriptiveness of switch compared to a chain of ifs, so I will concentrate on part 2.

If the number of switch labels is N, a chain of ifs takes O(N) to dispatch, while a switch always dispatches in O(1). This is how it is done: compiler places addresses of switch labels into an array, computes an index based on the label values, and performs a jump directly, without comparing the switch expression to value one by one. In case of strings used as switch labels, the compiler produces a hash table, which looks up an address in O(1) as well.

When the number of switch becomes high (above 100), converting between switch and a chain of ifs could no longer be regarded as a micro-optimization: time savings may be very significant, especially in tight loops. If a profiler tells you that your chain of ifs is taking a significant time, rewriting as a switch may very well be a solution.

Quelle: https://softwareengineering.stackex...atement-better-than-a-series-of-if-statements

Heißt für mich das das kleinere if-else Ketten (1 - 10) geordnet von oben nach unten nach dem Fall der am wahrscheinlichsten Eintreten wird schneller sind als ein switch. Bei größeren wäre jedoch ein switch besser.
 

mrBrown

Super-Moderator
Mitarbeiter
Code:
A switch compiles into a lookup table which is fundamentally different then the if/else statements. If the last statement in a if/else chain is the one you want you have to check all the previous if/else first. This is not the case with a switch.
Code:
The power of switch is twofold:
[LIST=1]
[*]It is more descriptive
[*]It saves CPU cycles
[/LIST]
Your post already comments on the descriptiveness of switch compared to a chain of ifs, so I will concentrate on part 2.

If the number of switch labels is N, a chain of ifs takes O(N) to dispatch, while a switch always dispatches in O(1). This is how it is done: compiler places addresses of switch labels into an array, computes an index based on the label values, and performs a jump directly, without comparing the switch expression to value one by one. In case of strings used as switch labels, the compiler produces a hash table, which looks up an address in O(1) as well.

When the number of switch becomes high (above 100), converting between switch and a chain of ifs could no longer be regarded as a micro-optimization: time savings may be very significant, especially in tight loops. If a profiler tells you that your chain of ifs is taking a significant time, rewriting as a switch may very well be a solution.

Quelle: https://softwareengineering.stackex...atement-better-than-a-series-of-if-statements

Heißt für mich das das kleinere if-else Ketten (1 - 10) geordnet von oben nach unten nach dem Fall der am wahrscheinlichsten Eintreten wird schneller sind als ein switch. Bei größeren wäre jedoch ein switch besser.
wobei man in dem Fall nicht den JIT-Compiler außer Acht lassen sollte - manches an solchen Optimierungen, was für "normale" Compiler gilt, gilt für die nicht mehr unbedingt.
Theoretisch ließen sich solche if-kaskaden auch genauso optimierten, wie der entsprechende switch (und ich hoffe ganz stark, dass jemand in naher Zukunft eine entsprechende Optimierung für Graal schreibt ;))
 

mrBrown

Super-Moderator
Mitarbeiter
Dabei waren in der Inputdatei einfach eine lange Zeichenfolge.
Das Überraschende:
Für die Datei mit 2.237.761 Zeichen hat der BIS ca. 5 Sekunden gebraucht.
Der BAIS war, zumindest bei dem Test oben, nach <100ms fertig.
Die beiden Outputdateien sind identisch.
Habe ich bei den Testprogrammen etwas falsch gemacht oder ist das BAIS wirklich so viel schneller? Nur *spoiler* profitiert das Hauptprogramm von diesem vermeintlichen Geschwindigkeitsvorteil nicht.

Das erste Problem dabei dürfte sein, dass die beiden direkt nacheinander laufen.
Während das erste läuft, dürften der Großteil der Optimierungen durchlaufen (also noch langsamer Code und zusätzlich der laufende Compiler), der zweite nutzt dann den optimierten Code (also schneller Code und kein Compiler).

Dazu sind beide Programme nicht das gelbe vom Ei.
In BIS liest du die Datei ein und überträgst die *gesamte* Datei dann Byte-weise in ein einzelnes Array, um dieses dann wieder Byte-Weise zu schreiben.

In BAIS überträgst du die Datei erst in einen Buffer (das, was bei BIS im Hintergrund passiert), und liest das dann über den ByteArrayStream wieder byte-weise aus.

Sinnvoll wäre eine Mischung: Blockweise einlesen (BIS oder direkt in Array) und dann daraus direkt schreiben (entweder wieder BIS oder übers Array iterieren).
 

mrBrown

Super-Moderator
Mitarbeiter
Dabei waren in der Inputdatei einfach eine lange Zeichenfolge.
Das Überraschende:
Für die Datei mit 2.237.761 Zeichen hat der BIS ca. 5 Sekunden gebraucht.
Der BAIS war, zumindest bei dem Test oben, nach <100ms fertig.
Die beiden Outputdateien sind identisch.
Habe ich bei den Testprogrammen etwas falsch gemacht oder ist das BAIS wirklich so viel schneller? Nur *spoiler* profitiert das Hauptprogramm von diesem vermeintlichen Geschwindigkeitsvorteil nicht.

Das erste Problem dabei dürfte sein, dass die beiden direkt nacheinander laufen.
Während das erste läuft, dürften der Großteil der Optimierungen durchlaufen (also noch langsamer Code und zusätzlich der laufende Compiler), der zweite nutzt dann den optimierten Code (also schneller Code und kein Compiler).

Dazu sind beide Programme nicht das gelbe vom Ei.
In BIS liest du die Datei ein und überträgst die *gesamte* Datei dann Byte-weise in ein einzelnes Array, um dieses dann wieder Byte-Weise zu schreiben.

In BAIS überträgst du die Datei erst in einen Buffer (das, was bei BIS im Hintergrund passiert), und liest das dann über den ByteArrayStream wieder byte-weise aus.

Sinnvoll wäre eine Mischung: Blockweise einlesen (BIS oder direkt in Array) und dann daraus direkt schreiben (entweder wieder BIS oder übers Array iterieren).
 

DrZoidberg

Top Contributor
...
Das Überraschende:
Für die Datei mit 2.237.761 Zeichen hat der BIS ca. 5 Sekunden gebraucht.
Der BAIS war, zumindest bei dem Test oben, nach <100ms fertig.
Die beiden Outputdateien sind identisch.
Habe ich bei den Testprogrammen etwas falsch gemacht oder ist das BAIS wirklich so viel schneller? Nur *spoiler* profitiert das Hauptprogramm von diesem vermeintlichen Geschwindigkeitsvorteil nicht.

Das Problem ist, dass du die available Methode ständig aufrufst, denn die ist relativ langsam. Und du brauchst sie auch nicht. Am besten entfernst du sämtliche Aufrufe von available in deinem gesamten Programm. Dann wird das ganze wahrscheinlich sehr viel schneller laufen.

Ich habe dein BIS Beispiel etwas abgeändert. Jetzt braucht es nur noch 45ms für 2,2 MB und 1,7s für 200MB.
Java:
long testTime1 = System.currentTimeMillis();
try(BufferedInputStream bis = new BufferedInputStream(new FileInputStream("test.txt"))) {
  try(BufferedWriter bwriter = new BufferedWriter(new FileWriter("testout1.txt"))) {
    int bytesRead;
    byte[] arr = new byte[1024*1024];
    while((bytesRead = bis.read(arr)) >= 0) {
      for(int i = 0; i < bytesRead; i++) {
        bwriter.write((char)arr[i]);
      }
    }
  } catch(IOException e1) {
    e1.printStackTrace();
  }
} catch(IOException e2) {
    e2.printStackTrace();
}
long testTime2 = System.currentTimeMillis();
System.out.println("Zeit: "+(testTime2-testTime1)+"ms");
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
S .exe Datei/Programm auslesen? Allgemeine Java-Themen 2
K Website in Programm einbinden und auslesen Allgemeine Java-Themen 2
Jose05 Umgang mit Exceptions in einen Programm Allgemeine Java-Themen 2
E Output Fehler (Java-Programm Kuchen) Allgemeine Java-Themen 11
S Java Programm lässt sich vom USB-Stick starten, aber nicht von HDD Allgemeine Java-Themen 16
R Programm führt Methoden gleichzeitig aus Allgemeine Java-Themen 2
T Der Aufruf von CMD-Programm Allgemeine Java-Themen 30
A Java Programm erstellen hilfe Allgemeine Java-Themen 10
Mike80 Processing Programm fiert ohne Arduino ein Allgemeine Java-Themen 2
B Mysteriöse Ergebnisse beim Baccarat Programm? Allgemeine Java-Themen 13
districon Programm zum Durchsuchen von (Ebay-)Artikeln Allgemeine Java-Themen 1
T Addons im eigenen Programm Allgemeine Java-Themen 1
Calli11 Was muss ich hier in die Main schreiben, damit das Programm ausgeführt wird? Allgemeine Java-Themen 4
S Formel für Sonnenwinkel in ein Programm überführen Allgemeine Java-Themen 11
Alex_99 Programm stürzt beim Aufruf der Funktion ab? Text ausgeben Allgemeine Java-Themen 45
B Java Programm auf virutellem Desktop laufen lassen? Allgemeine Java-Themen 1
L Java überprüfen lassen, ob sich ein gegebener Pfad / das Programm an sich auf einer CD oder Festplatte befindet Allgemeine Java-Themen 14
Tiago1234 Warum hängt sich mein Programm auf? Allgemeine Java-Themen 22
D Programm designen Allgemeine Java-Themen 1
S Folgendes Problem bei einem Programm Allgemeine Java-Themen 1
J c Programm läuft nicht in compilierter Version des Java Projektes Allgemeine Java-Themen 7
O 2D-Grafik BioFarben-Programm soll auf Vollbild schalten Allgemeine Java-Themen 1
S Nachrichten Filter Programm Allgemeine Java-Themen 14
S Programm schreiben, das mir aufgrund von Schlagwörtern, die ich im Internet suche, relevante Themen sofort anzeigt. Allgemeine Java-Themen 1
T Hilfe bei Programm. IDE: Eclipse mit EV3-Plugin, lejos Allgemeine Java-Themen 8
Lukas2904 Swing Anzeigen lassen das das Programm geschlossen wurde Allgemeine Java-Themen 3
TechnikTVcode Mail Programm Allgemeine Java-Themen 2
S Programm entwickeln, welches ein Dreieckspuzzle lösen kann Allgemeine Java-Themen 5
R Lesen von Interfaces (Programm Vervollständigen) Allgemeine Java-Themen 10
Dann07 Java-Programm findet DLLs nicht! Allgemeine Java-Themen 20
OSchriever Linux-Programm öffnen Allgemeine Java-Themen 6
P USER Management in SQL übergreifend auf JAVA Programm Allgemeine Java-Themen 41
L Eclipse Konsole im exportierten Programm Allgemeine Java-Themen 2
OSchriever Programm über Linux-Kommandozeile ausführen Allgemeine Java-Themen 20
D Verkauf von einem Programm welches ich in Java geschrieben habe Allgemeine Java-Themen 4
M Programm erkennt String aus .txt Datei nicht Allgemeine Java-Themen 3
P Erstelltes Programm ist doppelt so groß Allgemeine Java-Themen 11
N Programm nach Abschluss neustarten lassen Allgemeine Java-Themen 6
S Einfaches Programm programmieren Allgemeine Java-Themen 5
M kleines KI Programm Idee Allgemeine Java-Themen 7
D Boolean von ein anderem Java Programm während der Laufzeit ändern Allgemeine Java-Themen 23
L Excel Datei löscht sich selbst im Programm - Java Allgemeine Java-Themen 3
I File ausführen und mein Programm bearbeiten lassen Allgemeine Java-Themen 11
ralfb1105 Starten Java App(s) (.jar) aus einem Java Programm Allgemeine Java-Themen 18
temi Java Programm aus einer DB laden und starten Allgemeine Java-Themen 2
N Programm startet nicht, nur per cmd Allgemeine Java-Themen 5
J Programm zum Suchen eines Wortes im Dateisystem Allgemeine Java-Themen 4
E Java Programm mit Clients erweitern - Möglichkeiten? Allgemeine Java-Themen 2
Joker4632 Methoden Befehl an bereits extern geöffnete Programm-spezifische Konsole senden Allgemeine Java-Themen 1
M Dieses Programm schneller machen? Allgemeine Java-Themen 2
R Programm zur Rekursion Allgemeine Java-Themen 5
N Quicksort Programm hängt sich auf Allgemeine Java-Themen 6
S Compiler-Fehler Programm verhält sich in Eclipse anders Allgemeine Java-Themen 1
dereki2000 Programm veröffentlichen Allgemeine Java-Themen 14
mrbig2017 Threads Chat Programm mit Threads? Allgemeine Java-Themen 2
M Suche aktuelle Apache Poi Bibliothek zum Einbinden in mein Programm Allgemeine Java-Themen 2
J Java "Bank Programm" Brauche eure Hilfe Allgemeine Java-Themen 3
S Java Programm (Spiel mit den Boxen) Allgemeine Java-Themen 1
kodela Programm hängt in der Ereigniswarteschlange Allgemeine Java-Themen 13
A Java Programm verbessern/vereinfachen Allgemeine Java-Themen 20
P Programm darf nicht mehrfach startbar sein Allgemeine Java-Themen 16
S Programm hängt sich manchmal (selten) auf Allgemeine Java-Themen 9
JavaNewbie2.0 Programm nicht im Taskmanager schliesen können Allgemeine Java-Themen 15
J XML Datei mit installiertem Programm öffnen Allgemeine Java-Themen 7
Arif Input/Output Dateien im Jar-Programm speichern Allgemeine Java-Themen 12
H Java FX 2 Fragen um Programm in mehrere sprachen zu übersetzen in Gluon Framwork Allgemeine Java-Themen 3
JavaNewbie2.0 Programm bleibt "stehen" Allgemeine Java-Themen 2
JavaNewbie2.0 Start eines Anderen Programm erkennen Allgemeine Java-Themen 6
E Mit Java ein Python Programm starten Allgemeine Java-Themen 20
Q-bert Daten von Java Programm speichern Allgemeine Java-Themen 4
Aruetiise Methoden .jar mit Programm öffnen Allgemeine Java-Themen 2
C anderes Programm schließen! Allgemeine Java-Themen 5
C Webseiten Programm problem Allgemeine Java-Themen 5
E Programm auf Installation prüfen Allgemeine Java-Themen 1
J Programm zum Download von CSV-Dateien Allgemeine Java-Themen 4
E Programm ohne Windowsrand(Vollbild) ? Allgemeine Java-Themen 5
G Programm, das nach abgearbeiteter main Methode weiterläuft Allgemeine Java-Themen 72
P Schnittstelle java Programm zu Webserver / Browser Allgemeine Java-Themen 2
J Schutz Programm Jar Exe Allgemeine Java-Themen 7
R javax.comm --> Programm funktioniert nach Export nicht mehr Allgemeine Java-Themen 0
Blender3D Java Swing Programm Windows 10 Autostart Problem Allgemeine Java-Themen 2
U Input/Output Warum wirft mir das Programm diesen Fehler? Allgemeine Java-Themen 6
X jvm exception abfangen und an externes Programm schicken Allgemeine Java-Themen 4
B Programm updaten mit FXLauncher Allgemeine Java-Themen 1
D Nicht quelloffenes Programm Allgemeine Java-Themen 5
F Java-Programm lizensieren Allgemeine Java-Themen 21
I Programm im Hintergrund bei Windows zur Steuerung der Tastatur nutzen Allgemeine Java-Themen 2
X Aus Programm "Installationsprogramm" machen Allgemeine Java-Themen 6
T Java Programm in Internetseite? Allgemeine Java-Themen 4
T Java Programm frisst RAM Allgemeine Java-Themen 6
H Alter Java-Programm läuft nicht mehr. Laut strace fehlt libpthread.so.0 Allgemeine Java-Themen 3
H Runtime reagiert erst wenn Programm abbricht Allgemeine Java-Themen 1
E Exceptions abfangen und dann Programm stoppen - aber wie? Allgemeine Java-Themen 2
Neumi5694 Offenes Programm nutzen Allgemeine Java-Themen 4
L Java-Programm Zahlenkombinationen ausgeben Allgemeine Java-Themen 10
KaffeeFan Methoden Suche Methode um Programm kurz warten zu lassen Allgemeine Java-Themen 22
J Programm meldet "Keine Rückmeldung" nach Verbindung zum Server Allgemeine Java-Themen 4
T Java Programm sauber beenden (Mac OS) Allgemeine Java-Themen 7
O Programm wird einfach "gekillt" Allgemeine Java-Themen 3
L TV Programm API/Web Service o.ä. Allgemeine Java-Themen 6

Ähnliche Java Themen


Oben