2011-10-24 48 views
9

(Este mensaje es con respecto a la programación de tipo de alta frecuencia)Cadena vs matriz de bytes, rendimiento

Hace poco vi en un foro (creo que estaban discutiendo Java) que si usted tiene que analizar una gran cantidad de datos de cadena que es mejor utilizar una matriz de bytes que una cadena con una división(). La publicación exacta fue:

Un truco de rendimiento para trabajar con cualquier idioma, C++, Java, C# es para evitar la creación de objetos. No es el costo de asignación o GC, es el costo para acceder a grandes matrices de memoria que no se ajustan a la memoria caché de la CPU.

Las CPU modernas son mucho más rápidas que su memoria. Se bloquean durante muchos, muchos ciclos por cada error de caché. La mayor parte del presupuesto de traspaso de CPU es asignado para reducir esto con cachés grandes y muchos tics.

GPU de resolver el problema de manera diferente por tener un montón de hilos listos para ejecutar para ocultar el acceso latencia de la memoria y tienen poca o ninguna memoria caché y pasar los transistores en más núcleos.

Por lo tanto, por ejemplo, en lugar de utilizar String y dividir para analizar un mensaje , utilice matrices de bytes que se puedan actualizar en su lugar. Realmente desea para evitar el acceso aleatorio a la memoria en estructuras de datos grandes, al menos en los bucles internos.

¿Simplemente dice "no uses cuerdas porque son un objeto y crear objetos es costoso"? ¿O está diciendo algo más?

¿El uso de una matriz de bytes garantiza que los datos permanezcan en la memoria caché el mayor tiempo posible? Cuando usa una cadena, ¿es demasiado grande para guardarla en la memoria caché de la CPU? Generalmente, ¿está utilizando los tipos de datos primitivos los mejores métodos para escribir código más rápido?

Respuesta

11

Está diciendo que si divide un trozo de texto en objetos de cadena separados, esos objetos de cadena tienen peor localidad que la matriz grande de texto. Cada cadena, y la matriz de caracteres que contiene, van a estar en otro lugar en la memoria; se pueden extender por todo el lugar. Es probable que la memoria caché tenga que entrar y salir para acceder a varias cadenas a medida que procesa los datos. Por el contrario, una matriz grande tiene la mejor localidad posible, ya que todos los datos están en un área de la memoria y la caché se reducirá a un mínimo.

Esto tiene sus límites, por supuesto: si el texto es muy, muy grande, y solo necesita analizar parte de él, entonces esas pocas cadenas pequeñas podrían caber mejor en la memoria caché que la gran cantidad de texto .

+0

Dijiste que "se pueden esparcir por todos lados". ¿Los caracteres de una Cadena están almacenados en la memoria continua, o como una lista vinculada? – user997112

+0

Los caracteres están en memoria continua. Pero, en general, un objeto de cadena consta de dos partes independientes: el objeto de cadena en sí y una matriz para contener los caracteres. Entonces, si crea muchas cadenas, cada una de esas cadenas, y cada una de sus matrices, está * en algún lugar *, y no hay garantía de que cualquiera de esa multitud de objetos va a estar en la misma región de memoria; cada uno, por separado, podría estar en cualquier parte. En C++, los objetos de cadena podrían estar en el mismo lugar si estuvieran asignados en una matriz de valores; en Java ni siquiera tendrías eso. –

+0

Los caracteres dentro de una cadena son continuos, sin embargo, si tiene varias cadenas, pueden estar por todos lados. Si utiliza String.substring en Java, es una vista de la cadena subyacente, por lo que esto no sucederá; sin embargo, C++ y C# toman copias de los datos de origen cuando toman una subcadena de otra Cadena. –

2

Hay muchas otras razones para usar byte[] o char* en lugar de cadenas para HFT. Las cadenas constan de 16 bits char en Java y son inmutables. byte[] o ByteBuffer son fáciles de reciclar, tienen buena ubicación de caché, pueden estar fuera del montón (directo) guardando una copia, evitando los codificadores de caracteres. Todo esto supone que está utilizando datos ASCII.

char* o los ByteBuffers también pueden asignarse a los adaptadores de red para guardar otra copia. (Con algunos ajustes para ByteBuffers)

En HFT, rara vez se trata de grandes cantidades de datos a la vez.Lo ideal sería que esté procesando datos tan pronto como baje del Socket. es decir, un paquete a la vez. (alrededor de 1,5 KB)

+0

¿Cómo mantendría una matriz de bytes fuera del montón, no tendría que usar 'nuevo' en la declaración? – user997112

+0

En C++, debe usar 'new' o' malloc' En Java, puede usar 'ByteBuffer.allocateDirect()' (que es un contenedor para un bloque de memoria 'malloc'ed) Usando reflection o JNI puede cambiar a dónde apunta la 'dirección' para que pueda acceder directamente a un adaptador de red (si está usando by-pass del kernel) Puede eliminar completamente el ByteBuffer si usa la clase' Inseguro' (aunque raramente hace una cantidad suficiente de diferencia) –

+0

Querido Peter, ¿podrías dar más detalles sobre "Al utilizar la reflexión o JNI puedes cambiar dónde apunta la dirección para que pueda acceder directamente a un adaptador de red (si estás utilizando un by-pass del kernel)". ¿Conoces algún sitio web con algún pequeño código de ejemplo? Supongo que esto es mucho más fácil de hacer en C++ que en Java? – user997112

Cuestiones relacionadas