javascript - new - nodejs tostring
¿Por qué los buffers transferidos están neutralizados en javascript? (7)
Javascript permite que los buffers se transfieran de un subproceso de origen a un subproceso de trabajo. De lo contrario, el ArrayBuffer se copia y luego se pasa al trabajador. Los buffers transferidos no son accesibles ("castrados") en el hilo fuente [1]:
// create data that can be transfered
var arr = new Uint8Array(5);
// outputs: 5
console.log(arr.buffer.byteLength);
var worker = new Worker("some_worker.js");
// transfer the buffer
worker.postMessage({arr: arr}, [arr.buff]);
// the buffer vanishes. is "Neutered"
// outputs: 0
console.log(arr.buffer.byteLength);
Entiendo cómo funciona el mecanismo. Sin embargo, tengo curiosidad de por qué se introdujo. ¿Por qué no se comparten los datos entre subprocesos de trabajo, como en un modelo de subprocesos tradicional, que permite que varios subprocesos accedan a la misma región de memoria?
Otras frases de la misma pregunta para aclarar:
¿Por qué se neutraliza el tampón en la transferencia? / ¿Cuál es el razonamiento detrás de este mecanismo? / ¿Por qué se introdujo? ¿Por qué no se pueden compartir regiones de memoria entre los trabajadores?
Estoy buscando una respuesta basada en fuentes creíbles y / o oficiales.
[1] https://developer.mozilla.org/en/docs/Web/API/Worker/postMessage
De acuerdo con el WHATWG ML, la elección era ser segura para las hebras , porque
No se pueden compartir datos entre trabajadores. No hay (y no puede haber) ningún estado compartido entre varios subprocesos de ejecución JS.
( source )
También,
Queremos que la fuente ArrayBuffer, y cualquier ArrayBufferViews, tenga una longitud cero al publicarlas en un trabajador o volver al hilo principal. Al hacer ping-pong en el mismo ArrayBuffer de un lado a otro, puede evitar asignar un nuevo almacén de respaldo a cada iteración.
( source )
Desafortunadamente, no encuentro la discusión sobre las especificaciones, la página donde debería estar alojada da 404, intentaré encontrar una copia en otro lugar
Esta es una pregunta muy básica de subprocesos múltiples. Si se pudiera acceder a la matriz tanto en el subproceso principal como en el trabajador, entonces debería implementarse un bloqueo de exclusión mutua para que no aparezcan condiciones de carrera al acceder al búfer. Además, creo que los búferes de arreglos generalmente se usan cuando se desea rendimiento, pero tener un bloqueo para leer / escribir datos de ese búfer haría al trabajador más lento.
Supongo que esta es una de las razones por las que el recurso se "mueve" y no se comparte.
TL; DR : multihilo
La razón es el rendimiento. Los datos enviados no se copian, la propiedad de ArrayBuffer se transfiere al receptor.
Para la memoria compartida, debe utilizar SharedArrayBuffer
Los objetos transferibles se introdujeron en los trabajadores web para mejorar el rendimiento en lugar de copiar objetos (especialmente cuando estamos hablando de objetos de gran tamaño). Puede ser paralelizado a una comparación entre paso por valor y paso por referencia en lenguajes de programación comunes (como C / C ++).
La restricción adicional, que los objetos transferibles no se pueden usar en el subproceso de trabajo de origen, probablemente se agregó, de modo que se garantice que no habrá condiciones de carrera entre los 2 subprocesos diferentes (para facilitar el trabajo de los desarrolladores que no tienen preocuparse por eso). Además, también sería necesario implementar muchas más primitivas de concurrencia en Javascript (como mutexes, etc.). En esencia, el uso de "transferencia" significa que solo tiene la intención de transferir los datos a otro subproceso, no usarlos desde 2 subprocesos simultáneamente, por lo que podríamos decir que la implementación tiene sentido.
En general, los Trabajadores Web no fueron diseñados como un modelo de memoria compartida, sino como un modelo de intercambio de mensajes.
Para leer más sobre la diferencia de rendimiento, verifique this . También puede verificar this , donde hay una discusión de por qué no se ha adoptado el modelo de memoria compartida para los trabajadores web en WebKit.
Para ser claros, las transferencias se aplican tanto a los trabajadores dedicados como a los compartidos, ya que ambos usan MessagePorts
[1] Los trabajadores dedicados usan objetos MessagePort detrás de escena.
[2] comunicación con trabajadores compartidos se realiza con objetos explícitos de MessagePort
postMessage se especifica para transferir o clonar según la elección del llamante :
[3] port.postMessage (mensaje [, transferencia]) publica un mensaje a través del canal. Los objetos enumerados en la transferencia se transfieren , no solo se clonan, lo que significa que ya no se pueden utilizar en el lado del envío.
Sin embargo, esto solo indica si el cartel conserva una copia, generalmente basada en la eficiencia, y no si se comparte alguna memoria.
Cuando se trata de " memoria ", se especifica claramente que no debe compartirse independientemente del tipo de trabajador o si los datos se transfieren o clonan :
[4] Cuando un agente de usuario debe ejecutar un trabajador para un script con URL url, un objeto de configuración de objeto de configuración de entorno y un referente de URL, debe ejecutar los siguientes pasos:
Cree un entorno de ejecución paralelo separado (es decir, un subproceso o proceso separado o construcción equivalente), y ejecute el resto de estos pasos en ese contexto.
Así que ahora la pregunta: ¿por qué? ¿Por qué el agente de usuario debe crear un entorno de ejecución paralelo para todos los tipos de trabajadores?
¿Seguridad? No. ¿Eficiencia? (¿Desde cuándo es js eficiente?), tampoco.
La razón es poder cumplir o, más bien, respetar la totalidad de la especificación. Si sigues el [4] , notarás como mínimo:
Cuando un agente de usuario debe terminar un trabajador, debe ejecutar los siguientes pasos en paralelo con el bucle principal del trabajador (el modelo de procesamiento "ejecutar un trabajador" definido anteriormente):
1) Establezca el indicador de cierre del objeto WorkerGlobalScope del trabajador en verdadero.
2) Si hay tareas en cola en las colas de tareas del bucle de eventos del objeto WorkerGlobalScope, descártelas sin procesarlas.
3) Abortar el script que se ejecuta actualmente en el trabajador.
4) Si el objeto WorkerGlobalScope del trabajador es en realidad un objeto DedicatedWorkerGlobalScope (es decir, el trabajador es un trabajador dedicado), vacíe la cola de mensajes del puerto del puerto con el que se enreda el puerto implícito del trabajador.
Y eso es solo una parte de la especificación.
Así que de nuevo, ¿por qué? Es para poder gestionar la totalidad de los eventos que tienen lugar en el espacio de trabajo. Los implementadores deben paralizar a los trabajadores o volverse completamente locos. :)
Para usar estos conceptos en javascript debes usar estos códigos,
PostMesage(aMessage, transferList)
En transferList debe especificar los objetos transferibles, que figuran en unMensaje:
var objData =
{
str: "string",
ab: new ArrayBuffer(100),
i8: new Int8Array(200)
};
objWorker.postMessage(objData, [objData.ab, objData.i8.buffer]);
On other side:
self.onmessage = function(objEvent)
{
var strText = objEvent.data.str;
var objTypedArray = objEvent.data.ab;
var objTypedArrayView = objEvent.data.i8;
}
Para usar "objetos transferibles", usted realmente transfiere la propiedad del objeto hacia o desde el trabajador web. Es como pasar por referencia donde no se hace una copia. La diferencia entre esto y el paso por referencia normal es que el lado que transfirió los datos ya no puede acceder a ellos.
Parece estar motivado por circunstancias históricas, ya que los transferibles se agregaron a la especificación después de que los trabajadores se introdujeran como API de paso de mensajes [1] con la intención de hacer cambios mínimos [2] [3].
[1] https://bugzilla.mozilla.org/show_bug.cgi?id=720083 (Solicitud de implementación en Firefox)
[2] https://mail.mozilla.org/pipermail/es-discuss/2014-May/037239.html
Porque cuando el concepto de Transferible se formalizó en la especificación HTML5, había un objetivo para hacer los mínimos cambios posibles. Transferible era básicamente una generalización de MessagePort, que era el único tipo que anteriormente podía ser "transferido" a un trabajador web. La neutralización es solo un concepto en el texto de especificaciones y no en el IDL. El typedef Transferible no tiene ningún método asociado. La única forma de neutralizar un objeto es transferirlo a un trabajador web. Hubo solicitudes para proporcionar un método "close ()" y hacer que Transferible sea una sub-interfaz de una nueva interfaz Closable. Nos resistimos a hacer esos cambios porque esencialmente habrían introducido la administración manual de memoria a JavaScript.
[3] https://mail.mozilla.org/pipermail/es-discuss/2014-May/037227.html
En primer lugar, algunos antecedentes. Cuando se diseñaron matrices escritas, se especificaron con Web IDL y su enlace ECMAScript. Hubo intentos durante el desarrollo de arrays tecleados para lanzar excepciones en algunas operaciones, como la indexación fuera del rango, pero se descubrió que una por una eran incompatibles con la semántica de Web IDL o ECMAScript como la búsqueda de propiedades.