logo java performance networking profiling netty

java - logo - hbase



Java: alternativa más rápida a String(byte[]) (3)

Estoy desarrollando un descargador basado en Java para datos binarios. Estos datos se transfieren a través de un protocolo basado en texto (UU-encoded). Para la tarea de red se usa la biblioteca de Netty . Los datos binarios se dividen por el servidor en muchos miles de pequeños paquetes y se envían al cliente (es decir, la aplicación Java).

Desde netty recibo un objeto ChannelBuffer cada vez que se recibe un nuevo mensaje (datos). Ahora necesito procesar esos datos, además de otras tareas, necesito verificar el encabezado del paquete que proviene del servidor (como la línea de estado HTTP). Para hacerlo, llamo a ChannelBuffer.array() para recibir una matriz de byte[] . Esta matriz puedo convertir en una cadena a través de una new String(byte[]) y verificar fácilmente (por ejemplo, comparar) su contenido (de nuevo, como una comparación con el mensaje de estado "200" en HTTP).

El software que estoy escribiendo usa múltiples hilos / conexiones, por lo que recibo múltiples paquetes de netty en paralelo.

Esto generalmente funciona bien, sin embargo, al perfilar la aplicación noté que cuando la conexión al servidor es buena y los datos llegan muy rápido, entonces esta conversión al objeto String parece ser un cuello de botella. El uso de CPU es cercano al 100% en tales casos, y de acuerdo con el generador de perfiles, se gasta mucho tiempo en llamar a este constructor de String(byte[]) .

Busqué una mejor manera de pasar del ChannelBuffer a un String , y noté que el primero también tiene un método toString() . Sin embargo, ese método es incluso más lento que el constructor String(byte[]) .

Entonces mi pregunta es: ¿Alguno de ustedes conoce una mejor alternativa para lograr lo que estoy haciendo?


¿Quizás podría saltear la conversión de cadena por completo? Podría tener constantes que contengan matrices de bytes para sus valores de comparación y comprobar array a array en lugar de String-to-String.

Aquí hay un código rápido para ilustrar. Actualmente estás haciendo algo como esto:

String http200 = "200"; // byte[] -> String conversion happens every time String input = new String(ChannelBuffer.array()); return input.equals(http200);

Tal vez esto es más rápido:

// Ideally only convert String->byte[] once. Store these // arrays somewhere and look them up instead of recalculating. final byte[] http200 = "200".getBytes("UTF-8"); // Select the correct charset! // Input doesn''t have to be converted! byte[] input = ChannelBuffer.array(); return Arrays.equals(input, http200);


Algunas de las comprobaciones que está haciendo podrían simplemente observar parte del buffer. Si pudiera usar la forma alternativa del constructor de cadenas:

new String(byteArray, startCol, length)

Eso podría significar que se convierten mucho menos bytes en una cadena.

Su ejemplo de buscar "200" dentro del mensaje sería un ejemplo.

2

Puede encontrar que puede usar la longitud de la matriz de bytes como una pista. Si algunos mensajes son largos y está buscando uno corto, ignore los largos y no los convierta a caracteres. O algo así.

3

Junto con lo que dijo @EricGrunzke, mirando parcialmente en el búfer de bytes para filtrar algunos mensajes y descubrir que no necesita convertirlos de bytes a caracteres.

4

Si sus bytes son caracteres ASCII, la conversión a caracteres podría ser más rápida si usa el juego de caracteres "ASCII" en lugar de usar el valor predeterminado para su servidor:

new String(bytes, "ASCII")

podría ser más rápido en ese caso.

De hecho, es posible que pueda seleccionar y elegir el juego de caracteres de conversión byte-carácter de una manera organizada que acelera las cosas.


Dependiendo de lo que estés tratando de hacer hay algunas opciones:

  1. Si solo está tratando de obtener el estado de respuesta, ¿no puede simplemente llamar a getStatus () ? Esto probablemente sería más rápido que sacar la cadena.
  2. Si está tratando de convertir el búfer, entonces, suponiendo que sepa que será ASCII, lo que suena como que lo hace, simplemente deje los datos como byte [] y convierta su método UUDecode para trabajar en un byte [] en lugar de un Cuerda.

El mayor costo de la conversión de cadenas es, con toda probabilidad, la copia de los datos de la matriz de bytes a la matriz de caracteres interna de la cadena, esto combinado con la conversión es muy probable que sea un montón de trabajo que no necesita hacer.