Introducción a la memoria compartida en JavaScript
Memoria compartida es una característica avanzada de JavaScript, que las hebras (partes de un proceso ejecutadas simultáneamente) pueden aprovechar. Compartir los medios de memoria. No tener la molestia de pasar datos actualizados entre subprocesos y todos los subprocesos pueden acceder y actualizar los mismos datos en la memoria compartida.
¿No suena encantador? Bueno, casi. En este post, ya veremos. Cómo usar la memoria compartida en JavaScript y cómo decidir si esto es lo que realmente quieres hacer.
Ventajas y desventajas de la memoria compartida
Usamos trabajadores web a crear hilos en JavaScript. La API de los trabajadores web nos permite crear subprocesos de trabajo que se pueden utilizar para Ejecutar código en segundo plano de modo que el subproceso principal esté libre para continuar su ejecución, posiblemente procesando eventos de UI, asegurando que no se congele la UI.
Hilos de trabajo Ejecutar simultáneamente con el hilo principal y entre sí. Dicha ejecución simultánea de diferentes partes de una tarea ahorra tiempo. Terminas más rápido, pero también tiene su propio conjunto de problemas..
Asegurándose de que cada hilo obtiene los recursos necesarios y se comunica entre sí de manera oportuna es una tarea en sí misma, donde un percance puede resultar en un resultado sorprendente. O si Un hilo está cambiando datos y otro lo está leyendo. al mismo tiempo, ¿Qué crees que verá el otro hilo? Los datos actualizados o antiguos.?
Sin embargo, los trabajadores de la web no son tan fáciles de joder. Durante su comunicación a través del uso de mensajes, los datos que se envían entre sí son no original sino una copia, lo que significa que no compartir Los mismos datos. Ellos pasar copias de los datos entre sí cuando sea necesario.
Pero compartir es importante, y es posible que varios subprocesos también deban mirar los mismos datos al mismo tiempo y cambiarlos. Asi que, Prohibir compartir es un gran no-no. Aquí es donde el SharedArrayBuffer
objeto entra en la imagen. Nos dejara compartir datos binarios entre múltiples hilos.
los SharedArrayBuffer
objeto
En lugar de pasar las copias de datos entre hilos, nosotros pasar copias de la SharedArrayBuffer
objeto. UNA SharedArrayBuffer
objeto Apunta a la memoria donde se guardan los datos..
Así, incluso cuando las copias de SharedArrayBuffer
se pasan entre hilos, ellos Todos seguirán apuntando a la misma memoria. donde se guardan los datos originales. Los hilos, así, pueden Ver y actualizar los datos en esa misma memoria..
Trabajadores web sin memoria compartida
Para ver cómo funciona un trabajador web sin usar memoria compartida, crear un hilo de trabajo y pasarle algunos datos.
los index.html
archivo contiene el guión principal dentro de una Etiqueta, como se puede ver a continuación:
const w = new Worker ('worker.js'); var n = 9; w.postMessage (n);
los worker.js
archivo lleva el guion del trabajador:
onmessage = (e) => console.group ('[worker]'); console.log ('Datos recibidos del hilo principal:% i', e.data); console.groupEnd ();
Usando el código de arriba, obtenemos lo siguiente salida en la consola:
[trabajador] Datos recibidos del hilo principal: 9
Puede leer mi publicación antes mencionada en los trabajadores web para obtener una explicación completa del código de los fragmentos anteriores..
Por ahora, tenga en cuenta que los datos son enviado de ida y vuelta entre hilos utilizando la mensaje posterior ()
método. Los datos son recibido en el otro lado por el mensaje
controlador de eventos, como el valor del evento datos
propiedad.
Ahora si nosotros cambiar los datos ¿Aparecerá actualizado en el extremo receptor? Veamos:
const w = new Worker ('worker.js'); var n = 9; w.postMessage (n); n = 1;
Como era de esperar, el datos tiene no sido actualizado:
[trabajador] Datos recibidos del hilo principal: 9
¿Por qué sería, de todos modos? Sus Solo un clon enviado al trabajador desde el script principal..
Trabajadores web con memoria compartida
Ahora lo haremos utilizar el SharedArrayBuffer
objeto en el mismo ejemplo Podemos crear un nuevo SharedArrayBuffer
instancia por utilizando la nuevo
palabra clave. El constructor toma un parámetro; una valor de longitud en bytes, especificando el tamaño del búfer.
const w = new Worker ('worker.js'); buff = new SharedArrayBuffer (1); var arr = new Int8Array (buff); / * ajuste de datos * / arr [0] = 9; / * enviando el búfer (copia) a worker * / w.postMessage (buff);
Tenga en cuenta que un SharedArrayBuffer
objeto representa solo un área de memoria compartida. A ver y cambiar los datos binarios, Necesitamos usar una estructura de datos apropiada TypedArray
o un DataView
objeto).
En el index.html
archivo de arriba, un nuevo SharedArrayBuffer
Se crea, con solo un byte de longitud. Entonces, un nuevo Int8Array
, que es un tipo de TypedArray
objetos, se usa para establecer los datos a “9” en el espacio de bytes proporcionado.
onmessage = (e) => var arr = new Int8Array (e.data); console.group ('[worker]'); console.log ('Datos recibidos del hilo principal:% i', arr [0]); console.groupEnd ();
Int8Array
También se usa en el trabajador, para ver los datos en el buffer.
los El valor esperado aparece en la consola. del hilo de trabajo, que es exactamente lo que queríamos:
[trabajador] Datos recibidos del hilo principal: 9
Ahora vamos a actualizar los datos en el hilo principal Para ver si el cambio se refleja en el trabajador..
const w = new Worker ('worker.js'), buff = new SharedArrayBuffer (1); var arr = new Int8Array (buff); / * ajuste de datos * / arr [0] = 9; / * enviando el búfer (copia) a worker * / w.postMessage (buff); / * cambiando los datos * / arr [0] = 1;
Y, como podéis ver más abajo, la actualización. se refleja dentro del trabajador!
[trabajador] Datos recibidos del hilo principal: 1
Pero, el código también necesita trabajar al revés: cuando el valor en el trabajador cambia al principio, también necesita ser actualizado cuando se imprime desde el hilo principal.
En este caso, nuestro código se ve así:
onmessage = (e) => var arr = new Int8Array (e.data); console.group ('[worker]'); console.log ('Datos recibidos del hilo principal:% i', arr [0]); console.groupEnd (); / * cambiando los datos * / arr [0] = 7; / * publicando en el hilo principal * / postMessage (");
los Los datos se cambian en el trabajador. y un mensaje vacío se publica en el hilo principal señalización de que los datos en el búfer se han cambiado y están listos para la salida del subproceso principal.
const w = new Worker ('worker.js'), buff = new SharedArrayBuffer (1); var arr = new Int8Array (buff); / * ajuste de datos * / arr [0] = 9; / * enviando el búfer (copia) a worker * / w.postMessage (buff); / * cambiando los datos * / arr [0] = 1; / * imprimiendo los datos después de que el trabajador los haya cambiado * / w.onmessage = (e) => console.group ('[main]'); console.log ('Datos actualizados recibidos del subproceso de trabajo:% i', arr [0]); console.groupEnd ();
Y esto también funciona.! Los datos en el búfer son los mismos que los datos dentro del trabajador.
[trabajador] Datos recibidos del hilo principal: 1 [principal] Datos actualizados recibidos del hilo del trabajador: 7
El valor Aparece actualizado en ambos casos.; Tanto el hilo principal como el de trabajo están viendo y cambiando los mismos datos.
Ultimas palabras
Como mencioné anteriormente, usar la memoria compartida en JavaScript No está sin desventajas. Depende de los desarrolladores asegurar que la secuencia de ejecución ocurre como se predijo y no hay dos hilos que estén compitiendo para obtener los mismos datos porque nadie sabe quién se llevará el trofeo..
Si está más interesado en la memoria compartida, consulte la documentación de Atomística
objeto. los El objeto atómico puede ayudarte con algunas de las dificultades., al reducir la naturaleza impredecible de la lectura / escritura de la memoria compartida.