Вопрос по javascript – Добавление ArrayBuffers

29

Каков предпочтительный способ добавления / объединения 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 имеют фиксированную длину, но необходимо ли инициализировать типизированные массивы? По прибытии я просто хочу иметь возможность обрабатывать буферы как буферы; типы и структуры не имеют значения.

@ Esailija Моя настоящая забота - производительность, хотя я еще не дошел до тестирования. Это просто выглядело как закулисный способ сделать это. Все еще привыкаю к JS! Спасибо, в любом случае user1421750
ну у тебя есть только.slice сArrayBuffer, с этим мало что можно сделать. Тогда у вас есть.append сBlobBuilder но это будет намного сложнее, чем то, что ты уже делаешь. Есть ли реальная проблема с вашим текущим подходом? Esailija
@ Esailija, решение вышеуказанного вопроса предлагает мой текущий подход, который объединяет типизированные массивы в новый буфер. Что хорошо, когда вы хотите иметь дело с типизированными массивами. Я хочу их вообще избежать. У меня вопрос, возможно ли это. user1421750

Ваш Ответ

3   ответа
-2

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

Как это лучше, чем Uint8Array для этой цели? BHSPitMonkey
@ BHSPitMonkey Это не совсем так - единственная причина упоминания о том, что он не принимает определенный тип элемента. Cyphus
Нет ничего плохого в том, чтобы рассматривать все как Uint8, если цель состоит в том, чтобы просто скопировать данные, как здесь. DataView хорош, если вам нужна гибкость, для которой он нужен, но он гораздо менее производительный для этой цели. Видеть: Jsperf.com / uint8array-против-dataview3 BHSPitMonkey
7

что это могло быть недоступно в то время).

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

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

РЕДАКТИРОВАТЬ

Я хотел сравнить эффективность этих двух методов (Blobs и метод, использованный в вопросе) и создал JSPerf:http: //jsperf.com/appending-arraybuffer

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

Но это асинхронно… Bergi
На самом деле, мне все еще легче пользоваться. Jb Drucker
@ Bergi Если вы используете его в Рабочие, вы можете использовать FileReaderSync. Константин Ван
@ JbDrucker Знаете ли вы, как и когда освобождается память для BLOB-объекта? Blob.close () в данный момент выглядит как бета-версия Doua Beri
Для меня сегодня (64-разрядная версия, Windows 10, Intel Core i7) в 4-й редакции вашего теста говорится, что использование Blobs в 2 раза быстрее в Firefox 56 и что appendBuffer в 6 раз быстрее в Chrome 61. John Glassmyer
0

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

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 уже есть место для динамически выделяемой памяти. Этот метод будет использовать это пространство вместо создания многочисленных новых выделений памяти, которые могут быть причиной снижения производительности в ядре операционной системы. Кроме того, вы также сможете сбрить несколько вызовов функций.

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

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

Похожие вопросы