¿La máquina virtual v8 está sujeta a restricciones de subprocesos?
Contexto: contexto de tiempo de ejecución, inicializado cuando se inicia el nodo (no vi mucho)
Aislado: dominio de aislamiento, que representa una instancia de la máquina virtual v8 , esta es la clave
HandleScope: dominio de manejo, o una colección de identificadores. Los objetos js existen en las referencias del montón. En c ++, los objetos js deben operarse a través de identificadores v8 (Handle es una colección). de identificadores. Cuando
se lanza un HandleScope, también se liberan todos los identificadores contenidos. Si se utiliza un objeto js en su código js, no hay nada, como
var zs =. new Person();
zs=1; // En este momento, el nuevo objeto Person() recién creado no se utilizará en su código js
Además, cuando Cuando no hay identificadores en su código C++, el objeto será recolectado por el recolector de basura de v8, es decir, el objeto será liberado. e., borre la memoria del montón.
Handle: Como se mencionó anteriormente, es una referencia a js en c++. Sus subclases son Local y Persistente, esta última no se reciclará cuando se recicle el campo handle, es decir, v8 retendrá una referencia al objeto para que no sea reciclado por el recolector de basura.
Locker/Unlocker: bloqueo absoluto de hilos de Isolate.
Contexto:
No sé mucho sobre Contexto, así que no lo explicaré aquí.
Aislar:
Esto es la clave entre las claves, la existencia de Isolate hace que no tenga sentido para el nodo implementar subprocesos múltiples en el nivel js. ¿Qué es el subproceso múltiple en el nivel js? ¿Qué es el subproceso múltiple en la capa js? Esto significa entregar una función js a un subproceso secundario para su ejecución. Primero, veamos la anotación Isolate, que se traduce aproximadamente de la siguiente manera:
Aislar representa una instancia del motor v8. v8 permite crear y ejecutar múltiples aislados en paralelo en múltiples subprocesos. El mismo Isolate solo puede ejecutarse en un hilo a la vez. Y se necesita un bloqueador/desbloqueador para sincronizar su ejecución
1. Los objetos js creados en un Isolate no se pueden usar en otro Isolate.
¿Qué significa esto? Los objetos js que creamos en c++ y js en realidad se almacenan en una instancia de Isolate. Puede considerar Isolate como un montón y los objetos js creados obtienen memoria de este montón. Pero los objetos que creo en este Aislar no se pueden utilizar en otro Aislar. Es como si tuviera dos archivos js que se inician dos veces con el nodo y los dos programas de nodo no pueden usar los objetos del otro.
//1.js
var a=1;
/2.js
console.log(a); / obviamente no está definido aquí porque la variable a no existe en 2.js.
Por supuesto, no hay ningún problema aquí, porque se podría decir que solo necesito usar un aislamiento para todos los subprocesos. Veamos la siguiente frase.
2. El mismo Isolate solo puede ejecutarse en un solo subproceso a la vez
Esta oración significa que el mismo Isolate solo puede ejecutarse en varios subprocesos en serie, por ejemplo, si hay uno. un hilo principal, un hilo a y un hilo b, y Isolate sale del hilo principal, por lo que Isolate solo puede ser utilizado por el hilo a, luego el hilo b espera a que Isolate salga del hilo principal.
¿Cuál es el resultado de esto? Usaré un ejemplo de código para ilustrar
// Supongamos que hay una función thread.run(fn,args,callback); args, ejecuta la devolución de llamada después de completar la devolución de llamada
thread.run(function(){
console.log('child thread');
},null, function (){
console.log('Ejecución del subproceso completada');
});
while(true){
console.log('El hilo principal ha estado imprimiendo...') )
}
// Según el entendimiento normal, se debe generar el siguiente contenido
...
...(se omite lo anterior)
El hilo principal ha estado imprimiendo...
El hilo principal ha sido imprimiendo...
Subproceso
...
El hilo principal ha estado imprimiendo...
El subproceso el hilo ha sido ejecutado
El hilo principal El hilo continúa imprimiendo...
...
...
Pero el nodo no puede hacer esto y la salida impresa es solo
Subproceso
Ejecución del subproceso completada
El subproceso principal continúa imprimiendo...
El hilo principal continúa imprimiendo...
...
Dado que fn, args y callback son objetos definidos en la zona de aislamiento, si fn quiere ejecutarse en un niño subproceso, el subproceso principal debe salir de la zona de aislamiento antes de que el subproceso secundario tome el control y ejecute fn y devolución de llamada, y luego El área de cuarentena se devuelve al subproceso principal.
2. Locker/Unlocker
El casillero es lo que yo llamo el casillero absoluto de subprocesos del área de aislamiento. Bloquea el área de aislamiento para el subproceso actual, por lo que otros subprocesos no pueden usarlo. . Cuarentena. Si no usa un candado, el subproceso secundario aún puede usar el Aislamiento del subproceso principal, pero se usa en serie, pero el Aislamiento bloqueado por el candado no está disponible en absoluto para otros subprocesos, y Unlocker debe liberar este método de bloqueo absoluto.
Sin bloqueo
//Aquí están los subprocesos
Aislar* aislar; //Supongamos que se trata de una instancia aislada pasada desde el hilo principal
isolate->Enter(); //Aislar ingresa al hilo actual, otros hilos no pueden usar el aislamiento
//...Después de 10,000 operaciones
aislar -> Salir(); //aislar la salida del hilo. Hilos adicionales ahora están disponibles.
Supongamos que el hilo principal agrega un candado
//Hilo principal
Locker(isolate);
isolate->Exit( ) ; //El hilo principal sale del aislamiento
//Subproceso
isolate->Enter();. //Error, no recuerdo el mensaje de error original, significa que el bloqueo no se usó en el momento adecuado.
3. Gestión de objetos js en v8
Este es un tema no relacionado con subprocesos múltiples, pero cuando se trata de v8, quiero hablar de ello.
Ya he hablado antes de Handle y HandleScope. Si has estudiado C++, debes saber que esto es lo que significa manejar. Si no ha aprendido C++, puede considerarlo como una referencia a un objeto de referencia.
En resumen, Handle no es un objeto js, es una referencia al objeto js. Puedo operar el objeto js a través de él. En este ejemplo, ningún Handle apunta al objeto js, al igual que en el ejemplo anterior. en js En el código, se reemplaza por un identificador, no por una variable que apunta a él (que en realidad es lo mismo aquí). En resumen, ya no podrá utilizar el objeto, ya no lo encontrará en su código y la recolección de basura de v8 lo borrará.
1. La zona de aislamiento es una instancia de v8, que es equivalente a un entorno de ejecución js. Todos sus objetos js deben crearse en esta zona de aislamiento
v8::Isolate: ::CreateParams params():: v8::Isolate::CreateParams params(): v8::Isolate:.HandleScope handle_scope(isolate); //Crea un campo de identificador para este aislamiento. Si no, v8 solicitará el campo creado. objeto js El identificador no tiene campo de identificador
v8::Handle
//Esta oración crea un identificador que apunta a un v8::String. Este es un objeto v8::String recién creado que se acaba de crear de forma aislada
/ /. ..Después de 10,000 líneas de código
isolate->Dispose(); //Después de liberar el área de aislamiento, se liberarán todos los identificadores y v8 borrará automáticamente todos los objetos js en el área de aislamiento.
Básicamente, todos los objetos v8 js se crean así: Handle
El tipo v8 es un tipo definido en js. Los tipos básicos incluyen:
Valor de cualquier tipo de valor
Objeto el valor del objeto
Valor de cadena de cadena
Valor numérico de número
Valor booleano de tipo booleano
Valor de función de función
Otros tipos de valores p >
Hay otros tipos además de este
Promesa significa Promesa
Promesa significa Promesa
Promesa significa Promesa
Promesa significa Promise
Promise representa Promise
FunctionCallbackInfo representa parámetros de función
4 Cómo usa Node v8
v8 no puede admitir subprocesos múltiples al mismo tiempo. js capa, dado que no puede pasar funciones, los objetos se pueden pasar a través de parámetros jsonizados, pero esto es un poco engorroso.
El nodo se puede dividir en dos partes
v8
API del nodo
Por ejemplo, fs.readFile(ruta,codificación,devolución de llamada );
El proceso de js llamando a esta función probablemente sea así
1. En el hilo principal, convierte el valor de la variable js en un valor de C++, por ejemplo, la ruta y la codificación se convierten en cadenas de C++ y se habilita un subproceso de C++ para realizar la operación readFile.
2. Envíe la tarea al sondeo de eventos y establezca el estado de la tarea en incompleto.
El subproceso io de 3.c++ completa la tarea y notifica al sondeo de eventos que la tarea se completó. .
4. Evento de sondeo de eventos, convierta el valor de retorno del subproceso de C ++ en un valor js en el área de aislamiento del subproceso principal y pase este valor como parámetro a la función de devolución de llamada, que debe aislarse. en el hilo principal ejecutado en el área.
Esto significa que el nodo convertirá el objeto v8 en un objeto c++ y el subproceso secundario convertirá el resultado nuevamente en un objeto v8 después de la ejecución. Ambas conversiones deben realizarse en la misma cuarentena. Por lo tanto, la funcionalidad asíncrona del nodo solo se puede proporcionar a través de la API basada en C++ sin implementar primero subprocesos múltiples a nivel de nodo, lo que en última instancia no está permitido en la versión 8.
5. Resumen
Inicialmente quería crear un complemento multiproceso para node, pero ahora me doy cuenta de que esto parece imposible.
Pienso mucho en la comunicación entre cuarentenas. Por ejemplo, si quiero que un subproceso secundario ejecute una función que contenga el objeto js de cuarentena actual, entonces pasaría ese objeto, lo convertiría a json, lo decodificaría en c++ y luego crearía un nuevo aislamiento y lo convertiría nuevamente a un objeto js. De esta forma, dos entidades aisladas pueden comunicarse, pero no se puede transferir la función. Y debe pasar todos los parámetros en tiempo de ejecución, por lo que no puede utilizar la funcionalidad de cierres js. Para hacer esto, probablemente necesitaría modificar el código fuente v8, pero mi C++ no es muy bueno y no puedo entenderlo en absoluto.
En cuanto al módulo threads_a_gogo, su api es eval (código js), lo que equivale a crear un nuevo contexto para ejecutar este script. Esto también equivale a la incapacidad de comunicarse entre compartimentos, lo que significa que las funciones y objetos ya creados no se pueden usar, solo se pueden usar algunas funciones básicas integradas en el nodo.
También existe un clúster, que es un módulo multiproceso que puede iniciar múltiples procesos para capturar el mismo script js, pero no existe ninguna relación entre los procesos a y no se puede usar el proceso b. Los objetos y funciones no se pueden distribuir, por lo que no se puede cruzar el límite de aislamiento.
Entonces, no es que el nodo no quiera realizar subprocesos múltiples, pero la versión 8 lo limita.