2010-02-04 36 views
16

Estoy tratando de pasar un byte [] que contiene caracteres ASCII a log4j, para iniciar sesión en un archivo usando la representación obvia. Cuando simplemente paso en el byt [], por supuesto, se trata como un objeto y los registros son bastante inútiles. Cuando intento convertirlos a cadenas usando new String(byte[] data), el rendimiento de mi aplicación se reduce a la mitad.Convertir bytes ASCII [] a String

Cómo puedo pasarlos eficientemente, sin incurrir en la penalización de aproximadamente 30us de tiempo de convertirlos en cadenas.

Además, ¿por qué tarda tanto tiempo en convertirlos?

Gracias.

Editar

debo añadir que estoy optmising de latencia aquí - y sí, 30us hace la diferencia! Además, estas matrices varían desde ~ 100 hasta miles de bytes.

Respuesta

13

Lo que se quiere hacer es proceso de retardo de la matriz de bytes [] hasta que log4j decide que lo que realmente quiere registrar el mensaje. De esta forma, podría iniciar sesión en el nivel DEPURAR, por ejemplo, mientras lo prueba y luego desactivarlo durante la producción. Por ejemplo, usted podría:

final byte[] myArray = ...; 
Logger.getLogger(MyClass.class).debug(new Object() { 
    @Override public String toString() { 
     return new String(myArray); 
    } 
}); 

Ahora usted no paga la multa de velocidad a menos que realmente registrar los datos, ya que el método toString no se llama hasta log4j decide que en realidad va a registrar el mensaje!

Ahora no estoy seguro de lo que quiere decir con "la representación obvia", así que he supuesto que quiere decir convertir a una Cadena reinterpretando los bytes como la codificación de caracteres predeterminada. Ahora bien, si se trata de datos binarios, esto obviamente no tiene valor. En ese caso, me gustaría sugerir el uso de Arrays.toString(byte[]) para crear una cadena con formato a lo largo de las líneas de

[54, 23, 65, ...] 
+2

Agradable, usando un registrador asíncrono esto mueve la conversión lejos de la ruta crítica. – jwoolard

16

ASCII es una de las pocas codificaciones que se puede convertir a/de UTF16 sin búsquedas aritméticos o de mesa por lo que es posible convertir manualmente:

String convert(byte[] data) { 
    StringBuilder sb = new StringBuilder(data.length); 
    for (int i = 0; i < data.length; ++ i) { 
     if (data[i] < 0) throw new IllegalArgumentException(); 
     sb.append((char) data[i]); 
    } 
    return sb.toString(); 
} 

Pero asegúrese de que realmente es ASCII, o que va a terminar con la basura.

+0

Gracias - esto lo bajó en aproximadamente un 60% ... – jwoolard

+0

Este código funciona para mí. Pero el nuevo String (byteArray) hizo que mi aplicación para Android fallara. Puedes explicar la diferencia? –

8

Si sus datos son de hecho ASCII (es decir, datos de 7 bits), entonces debe usar new String(data, "US-ASCII") en lugar de depender de la codificación predeterminada de la plataforma. Esto puede ser más rápido que tratar de interpretarlo como la codificación predeterminada de su plataforma (que podría ser UTF-8, que requiere más introspección).

También puede acelerar esto evitando el golpe Charset-Lookup cada vez, almacenando en caché la instancia Charset y llamando al new String(data, charset) en su lugar.

Una vez dicho esto: Ha sido un tiempo muy, muy largo tiempo desde que he visto datos reales ASCII en el entorno de producción

+0

¿cuál es la diferencia entre esto y la respuesta de finnw? – Zyoo

+2

Depende del entorno de producción en el que se encuentre, señor. Lo veo todos los días. – RW4

1

rendimiento reducido a la mitad? ¿Qué tan grande es esta matriz de bytes? Si es, por ejemplo, 1MB, entonces hay más factores a tener en cuenta que simplemente "convertir" de bytes a caracteres (que se supone que es lo suficientemente rápido).Escribir 1MB de datos en lugar de "solo" 100bytes (que el byte[].toString() puede generar) en un archivo de registro obviamente va a tomar algún tiempo. El sistema de archivos de disco no es tan rápido como la memoria RAM.

Tendrá que cambiar la representación de la cadena de bytes. Tal vez con algo de información más sensible, p. el nombre asociado con él (nombre de archivo?), su longitud, etc. Después de todo, ¿qué representa esa matriz de bytes en realidad?

Editar: No puedo recordar haber visto el "aproximadamente 30us" frase en su pregunta, tal vez haya editado en el plazo de 5 minutos después de pedir, pero esto es en realidad microoptimization y debe ciertamente no causa "rendimiento reducido a la mitad" en general. A menos que los escriba un millón de veces por segundo (aún así, ¿por qué querría hacer eso? ¿No está abusando del fenómeno "registro"?).

+0

Estas matrices varían enormemente, desde aproximadamente 150 bytes hasta 4000 bytes. re. su último punto, estoy optimizando la latencia en lugar del rendimiento, por lo que necesito mover esta conversión fuera de la ruta crítica o acelerarla ... – jwoolard

+0

Además, lamentablemente es necesario registrar todos estos datos, y sí , es MUCHA cantidad de datos ... – jwoolard

+0

Entonces su cuello de botella está más en el disco IO que en el código Java, como esperaba. – BalusC