2010-05-06 28 views
10

En un programa que estoy escribiendo estoy haciendo mucha manipulación de cadenas. Estoy tratando de aumentar el rendimiento y me pregunto si el uso de matrices de caracteres mostrará un aumento de rendimiento decente. ¿Alguna sugerencia?Java Optimization String vs Char Arrays

+0

@ThePinkPoo: su pregunta carece de requisitos: ¿qué cadena se supone que debe contener? El rango completo de Unicode (en cuyo caso el uso de char [] demostrará ser un gran dolor ya que un * char * de Java es ** TOTALMENTE INADECUADO ** para representar los nuevos puntos de código Unicode introducidos en Unicode 3.1 y superiores)? ¿Solo (un subconjunto de) ASCII? En este último caso, puede volver a implementar toda la clase String respaldada solo por bytes y se puede realizar una gran cantidad de * muy * ingeniosas optimizaciones. He estado allí, hecho eso, procesando cientos de megabytes de archivos de texto ASCII en Java ... – SyntaxT3rr0r

Respuesta

7

¿Qué tipo de manipulación estás haciendo? ¿Puedes publicar una muestra de código?

Es posible que desee echar un vistazo a StringBuilder que implementa CharSequence para mejorar el rendimiento. No estoy seguro de que quieras lanzar el tuyo. StringBuilder no es seguro para subprocesos ... si quieres seguridad de subprocesos mira StringBuffer.

+0

Si necesita seguridad de hilos, hay una posibilidad no trivial de que tendrá que hacer algo más que simplemente colocar un 'StringBuffer'. Puede evitar interbloqueos y condiciones de carrera, pero los resultados probablemente no coincidan con lo que esperaba. –

+0

Gracias, volveré a implementar y luego publicaré mis resultados. – ThePinkPoo

+0

@Hank: con una actualización no trivial, envuelve su propio 'sincronizado (thebuffer) {...}' alrededor, pero no necesita ese tipo de cosas con demasiada frecuencia. De hecho, es por eso que se introdujo 'StringBuilder'; para deshacerse del costo de mantener bloqueos cuando no es necesario (es decir, casi todo el tiempo). –

2

La cadena ya está implementada como una matriz de caracteres. ¿Qué planeas hacer de manera diferente? De todos modos, entre eso y el hecho de que GC para objetos efímeros es extremadamente rápido, me sorprendería si pudiera encontrar una manera de aumentar el rendimiento sustituyendo las matrices de caracteres.

El consejo de Michael Borgwardt sobre matrices de caracteres pequeños y el uso de StringBuilder y StringBuffer es muy bueno. Pero para mí lo principal es tratar de no adivinar qué es lento: hacer mediciones, usar un generador de perfiles, obtener algunos hechos definitivos. Porque usualmente nuestras conjeturas sobre el rendimiento resultan ser incorrectas.

1

Cuando tiene una gran cantidad de cadenas cortas, utilizar char[] en su lugar puede ahorrar bastante memoria, lo que también significa más velocidad debido a menos errores de caché.

Pero con cadenas grandes, lo principal a tener en cuenta es evitar copias innecesarias resultantes de la inmutabilidad de String. Si hace un montón de concatenar o reemplazar, usar StringBuilder puede hacer una gran diferencia.

+0

Michael, ¿podría explicar un poco más sobre la sustitución de cadenas con char []? Char [] ocupará un poco menos de espacio que una instancia de String, sin embargo, char [] no se internaliza y para muchas cadenas cortas la probabilidad de que algunas de las cadenas sean iguales e internalizadas (es decir, JVM mantendrá una copia única)) es mucho más alto que para algunas cadenas largas. –

+0

@Totophil: Realmente depende del tipo de cadenas con las que trabajes y qué haces con ellas; Si usa representaciones mutables, el internado se vuelve irrelevante. –

+0

Michael, de acuerdo, realmente depende de los detalles del escenario. Y el único escenario que me viene a la mente es cuando el software necesita hacer muchas manipulaciones de cadenas "en su lugar". Pero el enfoque no será de ninguna ayuda para abordar los gastos indirectos de las cadenas provenientes de la concatenación, las búsquedas y las comparaciones. –

2

Aquí es un extracto de la full source of String class de JDK 6.0:

public final class String implements java.io.Serializable, 
     Comparable<String>, CharSequence { 
     /** The value is used for character storage. */ 
     private final char value[]; 

     /** The offset is the first index of the storage that is used. */ 
     private final int offset; 

     /** The count is the number of characters in the String. */ 
     private final int count; 

Como se puede ver internamente el valor ya está almacenado como un array de caracteres. Una matriz de caracteres como estructura de datos tiene todas las limitaciones de la clase String para la mayoría de las manipulaciones de cadenas: las matrices Java no crecen, es decir, cada vez que la cadena necesita crecer necesita una cadena. para asignar una nueva matriz y copiar los contenidos.

Como se sugirió anteriormente, tiene sentido usar StringBuilder o StringBuffer para la mayoría de las manipulaciones de cadenas.

De hecho el siguiente código:

String a = "a"; 
    a=a+"b"; 
    a=a+"c"; 

Cuando compilado serán convertidos automáticamente para utilizar StringBuilder, esto se puede comprobar fácilmente con la ayuda de javap. Como regla general, rara vez es recomendable perder tiempo tratando de mejorar el rendimiento de las clases básicas de Java, a menos que sea un experto de clase mundial en el asunto, simplemente porque este código fue escrito por los expertos de clase mundial en la materia. primer lugar.

2

¿Olvidó su contraseña? ¿Sabes dónde están los cuellos de botella? Ese es el primer paso si el rendimiento es inferior. Bueno, eso y definir qué son las métricas de rendimiento aceptables.

Una vez que haya perfilado algunas tareas, tendrá porcentajes de tiempo dedicado a hacer cosas. Si pasas mucho tiempo manipulando cadenas, ¿quizás puedes comenzar a guardar algunas de esas manipulaciones?¿Estás haciendo algunos de ellos repetidamente cuando hacerlos solo una vez sería suficiente (y luego usar ese resultado más tarde cuando sea necesario)? ¿Estás copiando cadenas cuando no es necesario? Recuerde, java.lang.String es inmutable, por lo que no se puede cambiar directamente.

He encontrado varias veces mientras optimizo/desempeño los sistemas de ajuste en los que trabajo que no sé de dónde proviene la lentitud instintivamente. He visto a otros (y, vergonzosamente, a mí mismo) pasar días optimizando algo que no muestra ninguna ganancia, porque no era el cuello de botella original, y de hecho era menos del 1% del tiempo pasado.

Espero que esto ayude a orientarlo en la dirección correcta.

+0

Tengo un perfil y no fue demasiado informativo ya que mi complejidad es bastante mínima. Sé por el perfil que los métodos de cadena lo estaban matando, también mis bucles dentro del código. Así que voy a desenrollar algunos de los bucles y usar StringBuilder – ThePinkPoo

+0

@ThePinkPoo: si las operaciones String lo están matando, entonces lo mejor que puede hacer es intentar y reducir el número de operaciones String que está haciendo. Esto se puede hacer mediante el almacenamiento en caché o un comportamiento similar. Perdón por suponer que no tenía perfil: a menudo lo veo en varias páginas de estilo de foro (aquí incluidas), y quería asegurarme de que lo estaba haciendo. :) Buena suerte. – aperkins