2010-05-25 11 views
6

Ho questo codice per concate alcuni elementi di matrice:Esiste un metodo più veloce di StringBuilder per una concatenazione massima di stringhe di 9-10 step?

StringBuilder sb = new StringBuilder(); 
private RatedMessage joinMessage(int step, boolean isresult) { 
     sb.delete(0, sb.length()); 
     RatedMessage rm; 
     for (int i = 0; i <= step; i++) { 
      if (mStack[i] == null) 
       continue; 
      rm = mStack[i].getCurrentMsg();// msg is built upfront, this just returns, it's a getter method call 
      if (rm == null || rm.msg.length() == 0) 
       continue; 
      if (sb.length() != 0) { 
       sb.append(", "); 
      } 
      sb.append(rm.msg); 
     } 
     rm.msg=sb.toString(); 
     return rm; 
    } 

Importante l'array contiene max 10 elementi, quindi non è abbastanza molto.

Il mio output di traccia mi dice che questo metodo è chiamato 18864 volte, il 16% del tempo di esecuzione è stato speso in questo metodo. Posso ottimizzare di più?

+0

Il tuo metodo dice che ha un tipo di ritorno di RatedMessage ma sembra restituire una stringa. Cosa sta succedendo? Inoltre, quanto sono grandi questi oggetti rm.msg, sono stringhe o c'è un implicito toString che viene chiamato su di loro? – luke

+0

Spiacente, ho ridotto il codice alla parte essenziale. C'è un tasso, il numero float per ogni messaggio. rm sta per RatedMessage. – Pentium10

+1

@ Pentium10, penso che tu abbia tagliato troppo. Hai un hotspot e in pratica stai assumendo che certe cose non siano il problema e poi chiedi del resto. Se hai un codice funzionante che hai dimostrato di essere lento ma più semplice (se rotto nel senso che dà la risposta sbagliata), è grandioso, ma non tagliare così tanto e aspettarti di ottenere una risposta significativa qui. – Yishai

risposta

3

alcune idee:

1) Se si inizializza lo StringBuilder con la capacità massima stimata? In questo modo è possibile risparmiare tempo impiegato nella ri-allocazione dell'array interno con la copia &.

2) È possibile aggiungere una virgola alla fine della sequenza e evitare la condizione per la lunghezza della stringa all'interno del ciclo. Invece, aggiungi una singola condizione alla fine del metodo e rimuovi la virgola finale se necessario.

5

Prima di tutto non riutilizzerò StringBuilder e creerò sempre nuove istanze. Questo sarà sicuramente più veloce, perché consentirebbe a GC di utilizzare un'area di heap di nuova generazione.

Un altro piccolo trucco che consente di eliminare almeno un'istruzione if è quello di riscrivere il codice come questo:

String separator = ""; 
    for (int i = 0; i <= step; i++) { 
     ... 
     sb.append(separator); 
     sb.append(rm.msg); 
     separator = ", "; 
    } 
+0

L'incarico extra sarà migliore per le prestazioni rispetto all'istruzione if? O è magicamente ottimizzato via dal compilatore? –

+0

Un altro modo per rimuovere quel if-block senza aggiungere l'assegnazione è spostare la condizione di uscita dall'intestazione del ciclo for e nel ciclo stesso: 'if (i <= step) break; sb.append (separator); ' –

0

Se si suppone che la funzione per concatenare gli elementi dell'array, perché stai passando in tutti questi valori folli e parametri inutilizzati?

private string joinMessage(string[] myArray) 
{ 
    StringBuilder sbr = new StringBuilder(); 
    for(int i = 0; i < myArray.Length; i++) 
    { 
    if(!string.IsNullOrEmpty(myArray[i]) 
    { 
     sbr.Append(myArray[i]); 
     sbr.Append(",") 
    } 
    } 
    return sbr.ToString(); 
} 
+0

Ho alcune altre cose minori in là, vedi il mio commento sulla domanda principale. – Pentium10

+0

Non sto sostenendo che non è necessario restituire mai un RatedMessage o fare qualcosa di simile, sto dicendo che se il punto del metodo è "Prende un array di stringhe e restituisce una stringa delimitata da virgole di tutti gli elementi concatenato ", qualsiasi cosa al di là di ciò è inutile (per il gusto di questa discussione) –

1

È possibile apportare la seguente modifica (che mostra solo le differenze):

String separator = ""; 
    for (int i = 0; i <= step; i++) { 
    // ... 
     sb.append(separator).append(rm.msg); 
     separator = ", "; 
    } 

E si libera se un extra se 9 volte a costo di aggiungere una stringa vuota una volta. Dovresti misurare se aiuta con i dati che stai usando prima di decidere di mantenere questo cambiamento :-)

0

Fai un passo attraverso ogni elemento nella pila prima, prendendo un conteggio della somma di tutte le lunghezze delle stringhe .

quindi è possibile utilizzare

sb.ensureCapacity(totalEndLength); 

costruttore String funziona come una lista di array, per cui si potrebbe essere ricostruire tale matrice con la maggior parte dei vostri accodamento.

0

Un po 'di mini-ottimizzazione ... prendere il test-per-virgola al di fuori del ciclo.

private RatedMessage joinMessage(int step, boolean isresult) { 
    sb.delete(0, sb.length()); 
    for (int i = 0; i <= step; i++) { 
     if (mStack[i] == null) 
      continue; 
     rm = mStack[i].getCurrentMsg(); 
     if (rm == null || rm.msg.length() == 0) 
      continue; 
     sb.append(rm.msg).append(", "); 
    } 
    if (sb.length() > 2) { 
     sb.delete(sb.length() - 2, 2); 
    } 
    return sb.toString(); 
} 

Altri suggerimenti sarebbe:

  • Assicurarsi che quando lo StringBuilder è costruito di impostare la sua lunghezza iniziale ad un discreto rapporto
  • non sono sicuro del contesto del resto della il codice, ma forse puoi assicurarti che mStack [i] non sia nullo, e che mStack [i] .getCurrentMessage() non sia nullo o vuoto - questo ti permetterà di prendere più istruzioni if ​​al di fuori del ciclo.
0

avere una copia separata del mStack array con la rappresentazione di stringa, per impostazione predefinita inizializzato con una stringa vuota, in modo che il ciclo potrebbe essere:

String [] mStackCopy = new String[]{"","","","","","","","","","",}; 
// or mstackCopy = new String[mStack.length]; 
// for(int i = 0 ; i < mStackCopy.lenght ; i++) { mStack[i] = "" } 

Inoltre, creare lo StringBuilder con una capacità sufficiente:

StringBuilder sb = new StringBuilder(10000);// 10k chars or whatever makes sense. 

Così, quando è necessario creare il messaggio che si sarebbe semplicemente:

for (int i = 0; i <= step; i++) { 
    sb.append(mStackCopy[i]); 
} 

E vuoti parti non causerà un problema, perché sono già vuoto:

Si può anche codice difficile:

sb.append(mStackCopy[0]); 
sb.append(mStackCopy[1]); 
sb.append(mStackCopy[2]); 
sb.append(mStackCopy[3]); 
sb.append(mStackCopy[4]); 
sb.append(mStackCopy[5]); 
sb.append(mStackCopy[6]); 
sb.append(mStackCopy[7]); 
sb.append(mStackCopy[8]); 
sb.append(mStackCopy[9]); 

Ma questo avrebbe causato più dolore che sollievo in futuro, garantito.

quando si aggiunge qualcosa al tuo mStack:

MStack item = new MStack(); 
item.setCurrentMessage("Some message"); 

.... 

Basta fare una copia del messaggio e aggiungere il "" già.

addToMStack(int position, MStackItem item) { 
    mStack[position] = item; 
    mStackCopy[position] = item.getCurrentMessage() + ", "; 
} 

E a seconda del verificarsi di valori nulli (se basso) si può prendere loro

addToMStack(int position, MStackItem item) { 
    if(item == null) { return; } 
    mStack[position] = item; 
    try { 
     mStackCopy[position] = item.getCurrentMessage() + ", "; 
    } catch(NullPointerException npe){} 
} 

Qual è orrendo

O convalidarlo:

addToMStack(int position, MStackItem item) { 
    if(item == null) { return; } 
    mStack[position] = item; 
    mStackCopy[position] = item.getCurrentMessage() + ", "; 
} 

Sono abbastanza sicuro che il tuo metodo sta facendo qualcos'altro che tu non mostrarci Probabilmente la ragione è lì.

Inoltre, il 16% non è così male, se 100% è 1 sec.

+0

Poiché sto eseguendo questo su un dispositivo mobile è molto più lento. Quanto sopra detto a 18864 passi ha richiesto 8-10 sec. – Pentium10

0

Se mStack è una raccolta anziché una matrice, è sufficiente eseguire mStack.toString(), che stamperà una stringa leggibile dell'array. Potrebbe essere più facile che scrivere il tuo.

0

16% runtime in questo metodo compreso o esclusi i metodi chiamati chiamati? La chiamata getCurrentMsg() potrebbe essere un problema nascosto, se crea molti oggetti.

Oltre a questo, suggerisco di prendere tutte le corde necessarie dal vostro stack e poi chiamare

StringUtils.join(myStrings, ", ")

utilizzando il Apache commons library. Prova a fare affidamento sul codice testato per cose di basso livello invece di ottimizzarlo ogni giorno. Alla fine ciò ti darà migliori risultati di ottimizzazione perché sarai in grado di concentrarti sul quadro generale (ovvero il design complessivo del tuo software).

+0

schiaffeggiandomi per non aver notato il commento oltre a quella chiamata. Tuttavia la raccomandazione StringUtils rimane. :) – Bananeweizen

+0

è inclusivo, l'esclusivo è il 12% qualcosa – Pentium10

0

A volte non c'è altro da ottimizzare. Penso che questo sia uno di questi casi.Puoi provare a radere un'istruzione o forse due, ma in linea di principio non la otterrai molto più velocemente.

Penso che l'unica cosa che rimane da ottimizzare è considerare perché lo si chiami 188.200 e se alcune di quelle chiamate possano essere evitate del tutto. Forse alcuni non sono necessari, o forse è possibile memorizzare il risultato in alcuni casi.

+0

fa parte di un processo di generazione macchina di stato, quando uno stato raggiunge uno stato di arresto, genera un risultato. È già stato ridotto in qualche modo dai valori 2M e viene chiamato solo 18k volte. – Pentium10

0

Utilizzare StringBuilder + StringUtils da Apache Commons Lang. Fare il giro di una stringa con un separatore e il chomping è ciò che è StringUtils!

private RatedMessage joinMessage(int step, boolean isresult) { 
     StringBuilder builder = new StringBuilder(); 
     for (int i = 0; i <= step; i++) { 
      WhateverTypeIsFromMStackVariable stackVariable = mStack[i]; 
      String message = getMessage(stackVariable); 
      if(StringUtils.isNotEmpty(message)) { 
       builder.append(message).append(", "); 
      } 
     } 
     RatedMessage rm = new RatedMessage(); 
     rm.msg = StringUtils.chomp(builder.toString(), ", "); 
     return rm; 
    } 

private static String getMessage(WhateverTypeIsFromMStackVariable stackVariable) { 
    if(stackVariable != null) { 
     RatedMessage message = stackVariable.getCurrentMsg(); 
     if(message != null) { 
      return message.msg; 
     } 
    } 
    return null; 
} 

Apache Commons Lang è qui: http://commons.apache.org/lang/

Problemi correlati