2012-05-28 12 views
27

¿Cuál es la forma preferible de agregar/combinar ArrayBuffers?Anexar ArrayBuffers

Estoy recibiendo y analizando paquetes de red con una variedad de estructuras de datos. Los mensajes entrantes se leen en ArrayBuffers. Si llega un paquete parcial, necesito almacenarlo y esperar el siguiente mensaje antes de volver a intentar analizarlo.

Actualmente estoy haciendo algo como esto:

function appendBuffer(buffer1, buffer2) { 
    var tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength); 
    tmp.set(new Uint8Array(buffer1), 0); 
    tmp.set(new Uint8Array(buffer2), buffer1.byteLength); 
    return tmp.buffer; 
} 

obvio que no puede moverse por tener que crear un nuevo buffer como ArrayBuffers son de una longitud fija, pero es necesario para inicializar matrices con tipo? Al llegar, lo único que quiero es poder tratar los buffers como buffers; tipos y estructuras no son importantes.

+2

posible duplicado de [matrices tipadas en Gecko 2: concatenación y expansión de array Float32] (http://stackoverflow.com/questions/4554252/typed-arrays-in-gecko-2-float32array-concatenation-and-expansion) – Esailija

+0

@Esailija, la solución a la pregunta anterior ofrece mi enfoque actual que combina matrices tipadas en un nuevo buffer. Lo cual está bien cuando quieres tratar con matrices tipadas. Quiero evitarlos por completo. Mi pregunta es si esto es posible. – user1421750

+2

bueno, solo tienes '.slice' con' ArrayBuffer', no se puede hacer mucho con eso. Luego tienes '.append' con' BlobBuilder' pero va a ser mucho más complicado que lo que ya estás haciendo. ¿Hay algún problema real con tu enfoque actual? – Esailija

Respuesta

-1

Usted podría utilizar siempre DataView (http://www.khronos.org/registry/typedarray/specs/latest/#8) en lugar de un conjunto de tipos específicos, pero como se ha mencionado en los comentarios a su pregunta, no se puede realmente hacer mucho con ArrayBuffer por su propia cuenta.

+0

¿Cómo sería eso mejor que un Uint8Array para este propósito? – BHSPitMonkey

+0

@BHSPitMonkey No es realmente, la única razón para mencionarlo es que no supone un tipo de elemento en particular. – Cyphus

+7

No hay nada de malo en tratar todo como un Uint8 si el propósito es simplemente copiar los datos, que es el caso aquí. DataView es ideal si necesita la flexibilidad que está ahí, pero es mucho menos eficiente para este propósito. Ver: http://jsperf.com/uint8array-vs-dataview3 – BHSPitMonkey

6

¿Por qué no usar un Blob? (Me doy cuenta de que podría no haber estado disponible en ese momento).

Simplemente cree un Blob con sus datos, como var blob = new Blob([array1,array2,string,...]) y vuélvalo a convertir en un ArrayBuffer (si es necesario) utilizando un FileReader (consulte this).

Comprobar esto: What's the difference between BlobBuilder and the new Blob constructor? Y esto: MDN Blob API

EDIT:

me querían comparar la eficiencia de estos dos métodos (gotas, y el método utilizado en la pregunta) y creó un JSPerf : http://jsperf.com/appending-arraybuffers

Parece que usar Blobs es más lento (De hecho, supongo que es el uso de Filereader para leer la Blob que lleva más tiempo). Así que ahora lo sabe;) Tal vez sería más eficiente cuando hay más de 2 ArrayBuffer (como la reconstrucción de un archivo a partir de sus fragmentos).

+0

Pero eso es asincrónico ... – Bergi

+0

De hecho, todavía me resulta más fácil de usar. –

+1

@Bergi Si lo usa en [Trabajadores] (https://developer.mozilla.org/en/DOM/Worker), puede usar [FileReaderSync] (https://developer.mozilla.org/en-US/ docs/Web/API/FileReaderSync). –

0

Parece que ya ha concluido que no hay forma de evitar la creación de un nuevo búfer de matriz. Sin embargo, por razones de rendimiento, podría ser beneficioso agregar los contenidos del búfer a un objeto de matriz estándar, luego crear un nuevo búfer de matriz o una matriz tipada a partir de ese.

var data = []; 

function receive_buffer(buffer) { 
    var i, len = data.length; 

    for(i = 0; i < buffer.length; i++) 
     data[len + i] = buffer[i]; 

    if(buffer_stream_done()) 
     callback(new Uint8Array(data)); 
} 

La mayoría de los motores de javascript ya tienen espacio reservado para la memoria asignada dinámicamente. Este método utilizará ese espacio en lugar de crear numerosas nuevas asignaciones de memoria, lo que puede ser un asesino de rendimiento dentro del núcleo del sistema operativo. Además de eso, también reducirás algunas llamadas a funciones.

Una segunda opción más complicada sería asignar la memoria de antemano. Si conoce el tamaño máximo de cualquier flujo de datos, entonces podría crear un búfer de matriz de ese tamaño, llenarlo (parcialmente si es necesario) y luego vaciarlo cuando termine.

Finalmente, si el rendimiento es su objetivo principal, y conoce el tamaño máximo de paquete (en lugar de la secuencia completa), comience con un conjunto de almacenamientos intermedios de matriz de ese tamaño. A medida que llena su memoria preasignada, cree nuevos búferes entre llamadas de red, de manera asíncrona, si es posible.