Frage

Ich versuche, ein gut optimiertes Code zu erstellen, um die Anzahl der X-Zigiten in Länge zu erstellen (wobei x aus einer Laufzeit-Eigenschaften-Datei gelesen wird) basierend auf einer DB-generierten Sequenznummer (y), die dann einen Ordner verwendet wird -name beim Speichern einer Datei.

Ich habe mir bisher drei Ideen ausgedacht, von denen das schnellste der letzte ist, aber ich würde mich über jeden Rat freuen, den die Leute dazu haben, ...

1) Instantieren Sie einen StringBuilder mit der anfänglichen Kapazität X. Gehen Sie Y an. Während die Länge <x ein Null bei POS Null einfügen.

2) Instantieren Sie einen StringBuilder mit der Anfangskapazität X. Während Länge <x eine Null anhängen. Erstellen Sie eine Dezimalformat basierend auf dem StringBuilder -Wert und formatieren Sie dann die Zahl, wenn sie benötigt wird.

3) Erstellen Sie eine neue INT von Math.Pow (10, x) und fügen Sie Y. verwenden String.ValueOf () auf die neue Zahl und dann Substring (1).

Der zweite kann offensichtlich in Abschnitte von Außenschleifen und Innenschleife aufgeteilt werden.

Also irgendwelche Tipps? Mit einer für Schleife von 10.000 Iterationen erhalte ich ähnliche Zeiten aus den ersten beiden, und die dritte Methode ist ungefähr zehnmal schneller. Scheint das richtig?

Voller Test-Methoden-Code unten ...

    // Setup test variables
    int numDigits = 9;
    int testNumber = 724;
    int numIterations = 10000;
    String folderHolder = null;
    DecimalFormat outputFormat = new DecimalFormat( "#,##0" );

    // StringBuilder test
    long before = System.nanoTime();
    for ( int i = 0; i < numIterations; i++ )
    {
        StringBuilder sb = new StringBuilder( numDigits );
        sb.append( testNumber );
        while ( sb.length() < numDigits )
        {
            sb.insert( 0, 0 );
        }

        folderHolder = sb.toString();
    }
    long after = System.nanoTime();
    System.out.println( "01: " + outputFormat.format( after - before ) + " nanoseconds" );
    System.out.println( "Sanity check: Folder = \"" + folderHolder + "\"" );

    // DecimalFormat test
    before = System.nanoTime();
    StringBuilder sb = new StringBuilder( numDigits );
    while ( sb.length() < numDigits )
    {
        sb.append( 0 );
    }
    DecimalFormat formatter = new DecimalFormat( sb.toString() );
    for ( int i = 0; i < numIterations; i++ )
    {
        folderHolder = formatter.format( testNumber );
    }
    after = System.nanoTime();
    System.out.println( "02: " + outputFormat.format( after - before ) + " nanoseconds" );
    System.out.println( "Sanity check: Folder = \"" + folderHolder + "\"" );

    // Substring test
    before = System.nanoTime();
    int baseNum = (int)Math.pow( 10, numDigits );
    for ( int i = 0; i < numIterations; i++ )
    {
        int newNum = baseNum + testNumber;
        folderHolder = String.valueOf( newNum ).substring( 1 );
    }
    after = System.nanoTime();
    System.out.println( "03: " + outputFormat.format( after - before ) + " nanoseconds" );
    System.out.println( "Sanity check: Folder = \"" + folderHolder + "\"" );
War es hilfreich?

Lösung

Ich würde aufhören, Optimierungen auf der Grundlage von Mikro-Benchmarks durchzuführen und etwas zu entscheiden, das elegante Codewese aussieht, wie z. String.format("%0"+numDigits+"d", testNumber)

Andere Tipps

Verwenden Sie String.Format ("%0 [Länge] d", i).

Für die Länge von 8 wäre es

String out = String.format("%08d", i);

Es ist langsamer, aber die Zeit, die das Tippen und Debuggen des komplexeren Codes aufgewendet hat, wird wahrscheinlich die gesamte zusätzliche Zeit überschreiten, die jemals während der Ausführung verwendet wurde.

Wenn Sie alle bereits damit verbrachten Mannschaftsstunden dazu addieren, übertrifft dies die Ausführungszeiteinsparungen höchstwahrscheinlich mit einem großen Faktor.

Das Einsetzen von Padding -Charakteren nacheinander ist offensichtlich langsam. Wenn die Leistung wirklich so groß ist, könnten Sie vordefinierte String-Konstanten von Lengts 1..N-1 stattdessen verwenden (wo n ist die größte erwartete Länge), die in einer Arraylist in den entsprechenden Indizes gespeichert ist.

Wenn n ist sehr groß, zumindest könnten Sie immer noch in größere Stücke anstelle von einzelnen Zeichen einfügen.

Wie auch andere auch betonten, ist die Optimierung nur dann machbar, wenn Sie Ihre Bewerbung unter realen Umständen vorgestellt haben und festgestellt haben, welcher spezifische Code der Engpass ist. Dann können Sie sich darauf konzentrieren (und natürlich das Profil erneut, um zu überprüfen, ob Ihre Änderungen die Leistung tatsächlich verbessern).

Hier ist eine Lösung, die im Grunde dasselbe ist wie Ihr StringBuilder mit zwei Optimierungen:

  1. Es schreibt direkt in ein Array, das den StringBuilder -Overhead umgeht
  2. Es führt die Operationen umgekehrt anstelle von Einfügen (0) aus, wodurch jedes Mal eine ArrayCopy wiedergegeben wird

Es macht auch die Annahmen, dass Numdigits> = zu den erforderlichen Zeichen sind, aber negative Zahlen ordnungsgemäß behandelt:

before = System.nanoTime();
String arrString=null;
for ( int j = 0; j < numIterations; j++ ){
  char[] arrNum = new char[numDigits];
  int i = numDigits-1;
  boolean neg = testNumber<0;
  for(int tmp = neg?-testNumber:testNumber;tmp>0;tmp/=10){
    arrNum[i--] = (char)((tmp%10)+48);
  }
  while(i>=0){
    arrNum[i--]='0';
  }
  if(neg)arrNum[0]='-';
  arrString = new String(arrNum);
}
after = System.nanoTime();
System.out.println( "04: " + outputFormat.format( after - before ) + " nanoseconds" );
System.out.println( "Sanity check: Folder = \"" + arrString + "\"" );

Diese Methode hat Ihre Proben auf meiner Maschine für Negative gut übertroffen und war für positive Vergleiche vergleichbar:

01: 18,090,933 nanoseconds
Sanity check: Folder = "000000742"
02: 22,659,205 nanoseconds
Sanity check: Folder = "000000742"
03: 2,309,949 nanoseconds
Sanity check: Folder = "000000742"
04: 6,380,892 nanoseconds
Sanity check: Folder = "000000742"

01: 14,933,369 nanoseconds
Sanity check: Folder = "0000-2745"
02: 21,685,158 nanoseconds
Sanity check: Folder = "-000002745"
03: 3,213,270 nanoseconds
Sanity check: Folder = "99997255"
04: 1,255,660 nanoseconds
Sanity check: Folder = "-00002745"

Bearbeiten: Ich bemerkte, dass Ihre Tests einige Objekte innerhalb der Iterationsschleife enthielten, die ich in meiner nicht durchgeführt hatte (z. B. Basenum in der Substring -Version nicht neu berechnet). Wenn ich die Tests so geändert habe, dass sie konsistent sind (keine Objekte / Berechnungen anwesend, wurde meine Version besser als Ihre durchgeführt:

01: 18,377,935 nanoseconds
Sanity check: Folder = "000000742"
02: 69,443,911 nanoseconds
Sanity check: Folder = "000000742"
03: 6,410,263 nanoseconds
Sanity check: Folder = "000000742"
04: 996,622 nanoseconds
Sanity check: Folder = "000000742"

Natürlich ist, wie andere erwähnt haben, dass Mikro -Benchmarking unglaublich schwierig / "fudgy" ist, wobei die gesamte Optimierung der VM und der Unfähigkeit, sie zu kontrollieren, durchgeführt wird.

Dies ist wahrscheinlich zusammen Link diskutiert viele Möglichkeiten, dies zu tun. Ich würde die Apache -Option empfehlen, Stringutils, sie kann das absolut schnellste sein oder auch nicht, aber es ist normalerweise eines der am einfachsten zu verstehen und hat die) & ##@ geschlagen, so dass es wahrscheinlich nicht brechen wird in einigen unvorhergesehenen Randfall. ;))

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top