2010-05-25 14 views
6

Tengo este código para concate algunos elementos de la matriz:¿Hay un método más rápido que StringBuilder para una concatenación máxima de 9-10 pasos?

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 la matriz tiene un máximo de 10 elementos, por lo que no es del todo mucho.

Mi salida de rastreo me dice que este método se llama 18864 veces, el 16% del tiempo de ejecución se gastó en este método. ¿Puedo optimizar más?

+0

Su método dice que tiene un tipo de retorno de RatedMessage pero parece devolver una cadena. ¿Que esta pasando? Además, ¿qué tan grandes son estos objetos rm.msg, son cadenas o hay un toString implícito siendo invocado sobre ellos? – luke

+0

Lo siento, reduje el código a la parte esencial. Hay una tasa, número flotante para cada mensaje. rm significa RatedMessage. – Pentium10

+1

@ Pentium10, creo que cortaste demasiado. Usted tiene un punto de acceso y básicamente está asumiendo que ciertas cosas no son el problema y luego pregunta por el resto. Si tiene un código de trabajo que ha demostrado que aún es lento pero es más simple (si está roto en el sentido de que arroja la respuesta incorrecta), es genial, pero no recorte tanto y espere obtener una respuesta significativa aquí. – Yishai

Respuesta

3

algunas ideas:

1) ¿Está de inicializar el StringBuilder con la capacidad máxima estimada? Esto puede ahorrar el tiempo pasado en la redistribución de la matriz interna & copiando.

2) Tal vez pueda añadir una coma en el lazo y evitar la condición de longitud de cadena dentro del ciclo. En su lugar, agregue una sola condición al final del método y elimine la coma final si es necesario.

5

Antes que nada no volveré a utilizar StringBuilder y siempre crearé una nueva instancia. Eso será ciertamente más rápido, porque permitiría a GC usar el área de almacenamiento de la generación joven.

Otro pequeño truco que permite eliminar al menos una sentencia if es volver a escribir el código de la siguiente manera:

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

¿La asignación adicional será mejor en cuanto a rendimiento que la instrucción if? ¿O está mágicamente optimizado por el compilador? –

+0

Otra forma de eliminar ese bloque if sin agregar la asignación es mover la condición de salida fuera del encabezado for-loop y dentro del bucle mismo: 'if (i <= step) break; sb.append (separator); ' –

0

Si se supone que su función para concatenar elementos de la matriz, ¿por qué estás de paso en todos estos valores locos y los parámetros no utilizados?

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

Tengo otras cosas menores allí, vea mi comentario sobre la pregunta principal. – Pentium10

+0

No estoy argumentando que no necesita devolver un RatedMessage ni hacer nada de eso, digo que si el objetivo del método es "Toma una matriz de cadenas y devuelve una cadena comma delimeted de todos los elementos concatenado ", cualquier cosa más allá de eso no tiene ningún valor (por el bien de esta discusión) –

1

Usted puede hacer el siguiente cambio (mostrando sólo las diferencias):

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

Se deshace si un extra si es 9 veces en el costo de agregar una cadena vacía una vez. Debe medir si ayuda en absoluto con los datos que está utilizando antes de decidir mantener este cambio :-)

0

Primero, recorra cada elemento de la pila, contando la suma de todas las longitudes de cadena .

continuación, puede utilizar

sb.ensureCapacity(totalEndLength); 

constructor de cadena funciona como una lista de arreglo, lo que podría ser la reconstrucción de esa matriz con la mayoría de sus APPENDs.

0

Un poco de una mini optimización ... saque la prueba de la coma fuera del circuito.

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(); 
} 

Otras sugerencias serían:

  • Asegúrese de que cuando se construye el StringBuilder ajuste su longitud inicial a un valor decente
  • No estoy seguro del contexto del resto de el código, pero tal vez pueda asegurarse previamente de que mStack [i] no será nulo, y que mStack [i] .getCurrentMessage() no es nulo o está vacío, esto le permitirá tomar más sentencias if fuera del ciclo.
0

dispone de una copia de la matriz mStack con la representación de cadena, por defecto inicializado con la cadena vacía, por lo que su bucle sería:

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

También, crear el StringBuilder con suficiente capacidad:

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

Por lo tanto, cuando se necesita para crear el mensaje que lo haría simplemente:

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

y vacío partes no causará un problema porque ya están en blanco:

Usted puede incluso codificar difícil que:

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]); 

Pero esto causaría más dolor que alivio en el futuro, garantizado.

cuando se agrega algo a su mStack:

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

.... 

Simplemente haga una copia del mensaje y añadir el "" ya.

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

Y dependiendo de la ocurrencia de valores nulos (si su baja) se puede coger ellos

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

Cuál es horrendo

o validar que:

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

Estoy bastante seguro de que su método está haciendo otra cosa que usted no nos muestres Probablemente la razón esté ahí.

Además, el 16% no es tan malo, si el 100% es 1 seg.

+0

Dado que estoy ejecutando esto en un dispositivo móvil es mucho más lento. Lo dicho anteriormente 18864 pasos tomó 8-10sec. – Pentium10

0

Si su mStack es una Colección en lugar de una matriz, puede simplemente hacer mStack.toString(), que imprimirá una cadena legible de la matriz. Eso podría ser más fácil que escribir el tuyo.

0

16% de tiempo de ejecución en este método incluyendo o excluyendo llamados métodos? La llamada getCurrentMsg() podría ser un problema oculto, si crea muchos objetos.

Además de eso, sugieren que tomar todas las cadenas necesarias de su pila y después llamar

StringUtils.join(myStrings, ", ")

utilizando el Apache commons library. Intente confiar en el código probado para tales cosas de bajo nivel en lugar de optimizarlo usted mismo cada dos días. Al final, obtendrá mejores resultados de optimización, ya que podrá concentrarse en la gran pantalla (es decir, el diseño general de su software).

+0

abofeteándome por no haber notado el comentario además de esa llamada. Sin embargo, la recomendación de StringUtils permanece. :) – Bananeweizen

+0

es inclusivo, exclusivo es 12% algo – Pentium10

0

A veces simplemente no hay nada más que optimizar. Creo que este es uno de esos casos.Puede tratar de afeitarse una o dos instrucciones, tal vez, pero en principio no lo conseguirá mucho más rápido.

Creo que lo único que queda por optimizar es considerar por qué lo está llamando 18864 veces y si algunas de esas llamadas se pueden evitar por completo. Tal vez algunos no sean necesarios, o quizás pueda almacenar el resultado en algunos casos.

+0

es parte de un proceso de generación de máquina de estado, cuando un estado alcanza el estado Detener, genera un resultado. Ya se ha reducido en cierto modo desde los valores de 2M solo se llama 18k veces. – Pentium10

0

Utilice StringBuilder + StringUtils de Apache Commons Lang. ¡Lo que se trata de StringUtils es atravesar una cadena con un separador y masticar!

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 está aquí: http://commons.apache.org/lang/

Cuestiones relacionadas