Question

Am essayant de créer un bit de code bien optimisé pour créer un nombre de X chiffres de longueur (où X est lue à partir d'un fichier de propriétés d'exécution), sur la base d'un numéro de séquence généré par DB (Y), qui est ensuite utilisé un nom de dossier lors de l'enregistrement d'un fichier.

Je suis venu avec trois idées à ce jour, ce qui est le dernier, mais j'apprécier les gens de conseil peuvent le plus rapide d'avoir sur ce ...

1) instancier un StringBuilder avec une capacité initiale X. append Y. Bien que la longueur

2) instancier un StringBuilder avec une capacité initiale X. Bien que la longueur

3) Créer un nouveau int de Math.pow (10, X) et ajoutez Y. Utilisez String.valueOf () sur le nouveau numéro, puis sous-chaîne (1) il.

Le second peut évidemment être divisé en dehors de boucle et à l'intérieur des sections en boucle.

Alors, des conseils? Je reçois les horaires similaires des deux premiers, et la troisième méthode est plus rapide d'environ dix fois l'aide d'une boucle for de 10.000 itérations,. Cela vous semble correct?

code de la méthode de test complet ci-dessous ...

    // 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 + "\"" );
Était-ce utile?

La solution

Je cesser de faire des optimisations à base de micro-benchmarks et aller pour quelque chose qui ressemble codewise élégant, comme String.format("%0"+numDigits+"d", testNumber)

Autres conseils

Utilisation String.format ( "% 0 [longueur] d", i)

Pour une longueur de 8, il serait

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

Il est plus lent, mais le temps passé à la saisie et le débogage du code plus complexe dépassera probablement le total de temps déjà utilisé lors de l'exécution.

En fait, si vous additionnez tous les hommes-heures déjà passé en discuter, il dépasse très probablement le gain de temps d'exécution d'un facteur important.

Insertion de caractères de remplissage, un par un est évidemment lent. Si la performance est vraiment un gros problème, vous pouvez utiliser les constantes de chaîne prédéfinies de lengts au lieu 1..n-1 (où n est la plus grande longueur attendue), stockée dans un ArrayList aux indices correspondants.

Si n est très grand, au moins, vous pouvez toujours insérer des morceaux plus gros en place de caractères simples.

Mais dans l'ensemble, comme d'autres ont souligné aussi, l'optimisation est uniquement possible si vous avez sélectionnés votre application dans des circonstances réelles et trouvé quel morceau de code spécifique est le goulot d'étranglement. Ensuite, vous pouvez concentrer sur ce (et du profil de cours pour vérifier que vos modifications améliorent réellement les performances).

Voici une solution qui est fondamentalement la même chose que votre StringBuilder avec deux optimisations:

  1. Il écrit directement à un tableau sans passer par les frais généraux StringBuilder
  2. Il fait les opérations en sens inverse au lieu d'insert (0), qui requries un arraycopy chaque fois

Il fait également les hypothèses qui seront numDigits> = aux caractères réels requis, mais gérer correctement les nombres négatifs:

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 + "\"" );

Cette méthode bien surperformé vos échantillons sur ma machine pour les négatifs et positifs était comparable:

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"

Modifier J'ai remarqué vos tests resued quelques-uns des objets dans la boucle d'itération, que je ne l'avais pas fait dans la mienne (par exemple, ne pas recalcul baseNum dans la version sous-chaîne). Lorsque j'ai modifié les tests pour être compatibles (non resuing des objets / calculs ma version réalisée mieux que le vôtre:

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"

Bien sûr, comme d'autres l'ont mentionné micro étalonnage est incroyablement difficile / « fudge » avec tous l'optimisation effectuée par la machine virtuelle et l'incapacité de les contrôler.

Ce lien discute probablement liés beaucoup de façons de le faire il. Je recommande l'option Apache, StringUtils, il peut ou ne peut pas être l'absolu le plus rapide, mais il est généralement l'un des plus faciles à comprendre, et a eu la) & ## @ pilonné de celui-ci, il ne sera probablement pas casser dans certains cas, de bord imprévu. ;)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top