ejemplos combinar codigo attribute javascript web-worker

javascript - combinar - title html



cómo pasar grandes datos a los trabajadores de la web (2)

Estoy trabajando en web workers y estoy transfiriendo gran cantidad de datos al web worker, lo que lleva mucho tiempo. Quiero saber la manera eficiente de enviar los datos.

He intentado con el siguiente código:

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


También tuve problemas con los webworkers, hasta que le pasé un único argumento al webworker.

Entonces, en lugar de

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

Tratar

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

De esta manera descubrí que se pasa por referencia y es increíblemente rápido. Publico ida y vuelta más de 20,000 elementos de datos en un solo empujón por 5 segundos sin que note la transferencia de datos. Sin embargo, he estado trabajando exclusivamente con Chrome, así que no sé cómo se mantendrá en otros navegadores.

Actualizar

He hecho algunas pruebas para algunas estadísticas.

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

resultados de las pruebas. No sé si esto cae en su categoría de lento o no, ya que no definió "lento"

  • enviando al 28837.418999988586
  • recibido en 28923.06199995801
  • 86 ms

  • enviando al 212387.9840001464

  • recibido en 212504.72499988973
  • 117 ms

  • enviando al 247635.6210000813

  • recibido en 247760.1259998046
  • 125 ms

  • enviando al 288194.15999995545

  • recibido en 288304.4079998508
  • 110 ms

ACTUALIZAR :

Según Mozilla, SharedArrayBuffer se ha desactivado en todos los navegadores principales, por lo que la opción descrita en el siguiente EDIT ya no se aplica.

Tenga en cuenta que SharedArrayBuffer se deshabilitó de forma predeterminada en todos los principales navegadores el 5 de enero de 2018 en respuesta a Spectre.

EDITAR: ahora hay otra opción y está enviando un búfer compartido Array. Esto es parte de ES2017 bajo memoria compartida y atómico y ahora es compatible con FireFox 54 Nightly. Si quieres leer sobre esto puedes mirar aquí . Probablemente escribiré algo en algún momento y lo agregaré a mi respuesta. Trataré de agregar al punto de referencia de rendimiento también.

Para responder la pregunta original:

Estoy trabajando en web workers y estoy transfiriendo gran cantidad de datos al web worker, lo que lleva mucho tiempo. Quiero saber la manera eficiente de enviar los datos.

La alternativa a la respuesta de @MichaelDibbets , su envía una copia del objeto al webworker, está usando un objeto transferible que es copia cero.

Muestra que intentabas transferir tus datos, pero supongo que no funcionó. Así que explicaré lo que significa que algunos datos sean transferibles para usted y los futuros lectores.

Transferir objetos "por referencia" (aunque ese no es el término perfecto para él, como se explica en la siguiente cita) no solo funciona en cualquier objeto de JavaScript. Tiene que ser un tipo de datos transferible.

[Con Web Workers] La mayoría de los navegadores implementan el algoritmo de clonación estructurado, que le permite pasar tipos más complejos dentro y fuera de Workers como File, Blob, ArrayBuffer y JSON. Sin embargo, al pasar estos tipos de datos utilizando postMessage (), aún se realiza una copia. Por lo tanto, si está transfiriendo un archivo grande de 50MB (por ejemplo), hay una carga perceptible para obtener ese archivo entre el trabajador y el hilo principal.

La clonación estructurada es excelente, pero una copia puede llevar cientos de milisegundos. Para combatir el golpe de perforación, puede usar Objetos transferibles.

Con Objetos transferibles, los datos se transfieren de un contexto a otro. Es cero copia, que mejora enormemente el rendimiento del envío de datos a un trabajador. Piense en ello como una referencia pasajera si pertenece al mundo de C / C ++. Sin embargo, a diferencia de la referencia de paso por paso, la ''versión'' del contexto de llamada ya no está disponible una vez que se transfiere al nuevo contexto. Por ejemplo, al transferir un ArrayBuffer de su aplicación principal a Worker, el ArrayBuffer original se borra y ya no se puede usar. Sus contenidos son (silenciosamente literalmente) transferidos al contexto del trabajador.

- Eric Biddleman Developer en Google, fuente: html5rocks.com/en/tutorials/workers/basics/#toc-transferrables

El único problema es que solo hay dos cosas transferibles a partir de ahora. ArrayBuffer y MessagePort . (Los Proxies de Canvas esperan llegar más tarde). Los ArrayBuffers no se pueden manipular directamente a través de su API y se deben usar para crear un objeto de matriz tipado o un DataView para dar una vista particular al búfer y poder leer y escribir en él.

Desde el enlace html5rocks

Para usar objetos transferibles, use una firma ligeramente diferente de postMessage ():

worker.postMessage(arrayBuffer, [arrayBuffer]);

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

El caso del trabajador, el primer argumento son los datos y el segundo es la lista de elementos que deben transferirse. El primer argumento no tiene por qué ser un ArrayBuffer por cierto. Por ejemplo, puede ser un objeto JSON:

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

Entonces de acuerdo a eso tu

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

debería funcionar a gran velocidad y debería transferirse a cero. El único problema sería si su buffer u obj.mat2 no es un ArrayBuffer o transferible. Puede confundir ArrayBuffers con una vista de una matriz tipada en lugar de utilizar el búfer.

Entonces, si tiene este ArrayBuffer y su representación Int32. (aunque la variable tiene el título view no es un DataView, pero DataView tiene un buffer de propiedades igual que las matrices tipadas. También en el momento en que esto fue escrito, el MDN usa el nombre ''view'' para el resultado de llamar a un constructor de matrices tipadas así que supuse que era una buena manera de definirlo.)

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

Esto es lo que no debes hacer (enviar la vista)

worker.postMessage(view);

Esto es lo que debes hacer (enviar el ArrayBuffer)

worker.postMessage(buffer, [buffer]);

Estos son los resultados después de ejecutar esta prueba en plnkr .

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

EDITAR: Como dice Bergi en los comentarios , no necesitas la variable de búfer en absoluto si tienes la vista, porque puedes simplemente enviar view.buffer como tal

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

Como una nota adicional para los lectores futuros que solo envían un ArrayBuffer sin el último argumento que especifica qué son los ArrayBuffers, no enviarán el ArrayBuffer de forma transferible

En otras palabras, al enviar transferencias, usted quiere esto:

worker.postMessage(buffer, [buffer]);

No esta:

worker.postMessage(buffer);

EDITAR: Y una última nota ya que está enviando un búfer no se olvide de convertir su búfer en una vista una vez que haya sido recibido por el webworker. Una vez que se trata de una vista, puede manipularla (leer y escribir a partir de ella) nuevamente.

Y por la recompensa:

También me interesan los límites de tamaño oficiales para Firefox / Chrome (no solo el límite de tiempo). Sin embargo, responda la pregunta original califica para la recompensa (;

En cuanto a un límite de webbrowsers para enviar algo de cierto tamaño, no estoy del todo seguro, pero a partir de esa cita de html5rocks por Eric Bidelman cuando hablaba de trabajadores, apareció un archivo de 50 mb que se transfería sin usar un tipo de datos transferibles en cientos de milisegundos y como se muestra a través de mi prueba en solo alrededor de un milisegundo usando un tipo de datos transferible. Cuál de 50 MB es honestamente bastante grande.

Puramente mi propia opinión, pero no creo que exista un límite en el tamaño del archivo que envía en un tipo de datos transferibles o no transferibles que no sean los límites del tipo de datos en sí. Por supuesto, su mayor preocupación probablemente sea que el navegador detenga secuencias de comandos de larga ejecución si tiene que copiar todo y no es de copia cero y transferible.

Espero que esta publicación te ayude. Honestamente, no sabía nada acerca de los transferibles antes de esto, pero fue divertido descifrarlos a través de algunas pruebas y a través de esa publicación en el blog de Eric Biddleman.