Добавление ArrayBuffers


Каков предпочтительный способ добавления / объединения ArrayBuffers?

Я принимаю и анализирую сетевые пакеты с различными структурами данных. Входящие сообщения считываются в ArrayBuffers. Если приходит частичный пакет, мне нужно сохранить его и дождаться следующего сообщения, прежде чем повторно пытаться его разобрать.

В настоящее время я делаю что-то вроде этого:

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;
}

Очевидно, что вы не можете обойти необходимость создания нового буфера, поскольку ArrayBuffers имеют фиксированную длину, но так ли это необходимо инициализировать типизированные массивы? По прибытии я просто хочу иметь возможность рассматривать буферы как буферы; типы и структуры не имеют никакого значения.

3 28

3 ответа:

Вы всегда можете использовать DataView (http://www.khronos.org/registry/typedarray/specs/latest/#8 ), а не конкретный типизированный массив, но, как уже упоминалось в комментариях к вашему вопросу, вы не можете сделать много с ArrayBuffer самостоятельно.

Почему бы не использовать Blob ? (Я понимаю, что в то время он, возможно, был недоступен).

Просто создайте большой двоичный объект с вашими данными, например var blob = new Blob([array1,array2,string,...]), и превратите его обратно в ArrayBuffer (при необходимости) с помощью FileReader (см. this).

Проверьте это: в чем разница между BlobBuilder и новым конструктором Blob? И это: MDN Blob API

Редактировать:

Я хотел сравнить эффективность этих двух методов (BLOB-объектов и метода используется в вопросе) и создал JSPerf: http://jsperf.com/appending-arraybuffers

Похоже, что использование BLOB-объектов медленнее (на самом деле, я думаю, что это использование Filereader для чтения Blob-объектов, которое занимает больше всего времени). Так что теперь ты знаешь ;) Возможно, это было бы более эффективно, когда есть более 2 ArrayBuffer (например, восстановление файла из его кусков).

Похоже, вы уже пришли к выводу, что нет способа обойти создание нового буфера массива. Однако для повышения производительности может оказаться полезным добавить содержимое буфера к стандартному объекту массива, а затем создать из него новый буфер массива или типизированный массив.

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));
}

Большинство движков javascript уже имеют некоторое пространство, отведенное для динамически выделяемой памяти. Этот метод будет использовать это пространство вместо создания многочисленных новых выделений памяти, которые могут быть убийца производительности внутри ядра операционной системы. Кроме того, вы также сбреете несколько вызовов функций.

Второй, более сложный вариант-это выделение памяти заранее. Если вы знаете максимальный размер любого потока данных, то вы можете создать буфер массива такого размера, заполнить его (частично, если это необходимо), а затем очистить его, когда это будет сделано.

Наконец, если производительность является вашей основной целью, и вы знаете максимальный размер пакета (вместо всего потока), то начните с горсткой буферов массива такого размера. По мере заполнения предварительно выделенной памяти создавайте новые буферы между сетевыми вызовами-по возможности асинхронно.