Подтвердить что ты не робот

Как передавать большие данные веб-работникам

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

Я пробовал следующий код:

var worker = new Worker('js2.js');
worker.postMessage( buffer,[ buffer]);
worker.postMessage(obj,[obj.mat2]);
if (buffer.byteLength) {
  alert('Transferables are not supported in your browser!');
}
4b9b3361

Ответ 1

EDIT: Теперь есть еще одна опция, и она отправляет буфер sharedArray. Это часть ES2017 под разделяемой памятью и атоматикой и теперь поддерживается в FireFox 54 Nightly. Если вы хотите прочитать об этом, вы можете посмотреть здесь. Я, вероятно, напишу что-нибудь и добавлю в ответ. Я также попытаюсь добавить к эталону производительности.

Чтобы ответить на исходный вопрос:

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

Альтернатива @MichaelDibbets answer, он отправляет копию объекта веб-работнику, использует передаваемый объект, который является нулевым.

Это показывает, что вы намеревались сделать ваши данные переносимыми, но я предполагаю, что это не сработало. Поэтому я объясню, что означает, что некоторые данные будут передаваться вам и будущим читателям.

Перенос объектов "по ссылке" (хотя это не идеальный термин для него, как объясняется в следующей цитате) не просто работает на любом объекте JavaScript. Он должен быть передаваемым типом данных.

[С веб-рабочими] Большинство браузеров реализуют структурированное клонирование алгоритм, который позволяет вам передавать более сложные типы в/из Рабочие, такие как файлы, объекты Blob, ArrayBuffer и JSON. Однако, при передаче этих типов данных с помощью postMessage() копия по-прежнему сделал. Поэтому, если вы передаете большой файл размером 50 МБ (например) там заметные накладные расходы при получении этого файла между работником и основной поток.

Структурированное клонирование велико, но копия может принимать сотни миллисекунды. Чтобы бороться с перфомансом, вы можете использовать Transferable Объекты.

С переносимыми объектами данные передаются из одного контекста в другой. Это нулевая копия, которая значительно улучшает производительность отправка данных рабочему. Подумайте об этом как об отправке, если вы из мира C/С++. Однако, в отличие от передачи по ссылке, "версия", из контекста вызова больше не доступен после переноса новый контекст. Например, при передаче ArrayBuffer из ваше основное приложение для Рабочего, оригинальный ArrayBuffer очищается, и нет более длительный срок годности. Его содержание (тихое буквально) передано в Рабочий контекст.

- Эрик Бидлман Разработчик в Google, источник: html5rocks

Единственная проблема в том, что на данный момент существует только две вещи, которые передаются. ArrayBuffer и MessagePort. (Canvas Proxies, надеюсь, придут позже). ArrayBuffers нельзя манипулировать напрямую через их API и использовать для создания типизированного объекта массива или DataView, чтобы дать конкретный вид в буфер и быть в состоянии читать и писать на него.

От ссылки html5rocks

Чтобы использовать передаваемые объекты, используйте несколько другую подпись PostMessage():

worker.postMessage(arrayBuffer, [arrayBuffer]);

window.postMessage(arrayBuffer, targetOrigin, [arrayBuffer]);

Рабочий случай, первым аргументом являются данные, а второй - список предметов, которые должны быть переданы. Первый аргумент не кстати, должен быть ArrayBuffer. Например, это может быть JSON Объект:

worker.postMessage({data: int8View, moreData: anotherBuffer}, [int8View.buffer, anotherBuffer]);

Итак, в соответствии с этим ваш

var worker = new Worker('js2.js');
worker.postMessage(buffer, [ buffer]);
worker.postMessage(obj, [obj.mat2]);

должен выполняться с большой скоростью и должен быть передан с нулевой копией. Единственная проблема заключается в том, что ваш buffer или obj.mat2 не является ArrayBuffer или передается. Возможно, вы сбиваете с толку ArrayBuffers с типизированными представлениями массивов вместо того, что вы должны использовать в нем.

Итак, если у вас есть это ArrayBuffer и это представление Int32. (хотя он имеет название, это не DataView, но DataView имеет буфер свойств так же, как и типизированные массивы. Также в то время, когда это было написано, MDN использует имя "view" для результата вызова типизированного массива-конструктора, поэтому Я предположил, что это хороший способ определить его.)

var buffer = new ArrayBuffer(90000000);
var view = new Int32Array(buffer);
for(var c=0;c<view.length;c++) {
    view[c]=42;
}

Это то, что вам нужно неdo (отправить представление)

worker.postMessage(view);

Это то, что вы должны делать (отправить ArrayBuffer)

worker.postMessage(buffer, [buffer]);

Это результаты после запуска этого теста на plnkr.

Average for sending views is 144.12690000608563
Average for sending ArrayBuffers is 0.3522000042721629

EDIT: как указано @Bergi в комментариях, вам не нужна переменная буфера при все, если у вас есть представление, потому что вы можете просто отправить view.buffer так:

worker.postMessage(view.buffer, [view.buffer]);

Как примечание к будущим читателям, просто отправляющее ArrayBuffer без последнего аргумента, определяющего, что такое ArrayBuffers, вы не отправите ArrayBuffer transferrably

Другими словами, при отправке передаваемых данных вы хотите:

worker.postMessage(buffer, [buffer]);

Не это:

worker.postMessage(buffer);

EDIT: И последнее примечание, так как вы отправляете буфер, не забудьте вернуть свой буфер обратно в представление после его получения веб-мастером. После того, как вы просмотрите его, вы можете снова его обрабатывать (читать и писать).

И за щедрость:

Меня также интересуют официальные ограничения размера для firefox/chrome (not только временные ограничения). Однако ответ на исходный вопрос подходит для щедрость (;

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

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

Надеюсь, что это сообщение поможет. Честно говоря, я ничего не знал о передатчиках до этого, но было интересно выяснить их через некоторые тесты и через это сообщение в блоге Эрика Бидманда.

Ответ 2

У меня также были проблемы с веб-мастерами, пока я просто не передал один аргумент веб-работнику.

Итак, вместо

worker.postMessage( buffer,[ buffer]);
worker.postMessage(obj,[obj.mat2]);

Try

var myobj = {buffer:buffer,obj:obj};
worker.postMessage(myobj);

Таким образом, я нашел, что его передают по ссылке и безумно быстро. Я отправляю туда и обратно более 20 000 наборов данных одним нажатием в течение 5 секунд без того, чтобы я не обратил внимание на datatransfer. Я работал исключительно с хром, поэтому я не знаю, как он будет задерживаться в других браузерах.

Обновление

Я провел некоторое тестирование для некоторых характеристик.

tmp = new ArrayBuffer(90000000);
test = new Int32Array(tmp);
for(c=0;c<test.length;c++) {
    test[c]=42;
}
for(c=0;c<4;c++) {
    window.setTimeout(function(){
        // Cloning the Array. "We" will have lost the array once its sent to the webworker. 
        // This is to make sure we dont have to repopulate it.
        testsend = new Int32Array(test);
        // marking time. sister mark is in webworker
        console.log("sending at at  "+window.performance.now());
        // post the clone to the thread.
        FieldValueCommunicator.worker.postMessage(testsend);
    },1000*c);
}

результаты испытаний. Я не знаю, относится ли это к вашей категории медленно или нет, так как вы не определили "медленный"

  • отправка по адресу 28837.418999988586
  • получено по адресу 28923.06199995801
  • 86 мс


  • отправка по номеру 212387.9840001464

  • получено по номеру 212504.72499988973
  • 117 мс


  • отправка по адресу: 247635.6210000813

  • получено по номеру 247760.1259998046
  • 125 мс


  • отправка по телефону 288194.15999995545

  • получен по адресу 288304.4079998508
  • 110 мс