He estado leyendo personalmente el código fuente de node.js & v8.
Entré en un problema similar como tú cuando traté de entender la arquitectura de node.js para escribir módulos nativos.
Lo que estoy publicando aquí es mi comprensión de node.js y esto también podría estar un poco fuera de lugar.
Libev es el bucle de eventos que realmente se ejecuta internamente en node.js para realizar operaciones simples de bucles de eventos. Está escrito originalmente para sistemas * nix. Libev proporciona un ciclo de eventos simple pero optimizado para que el proceso se ejecute. Puedes leer más sobre libev aquí .
LibEio es una biblioteca para realizar entradas y salidas de forma asincrónica. Maneja descriptores de archivos, manejadores de datos, sockets, etc. Puede leer más sobre esto aquí .
LibUv es una capa de abstracción en la parte superior de libeio, libev, c-ares (para DNS) y iocp (para windows asynchronous-io). LibUv realiza, mantiene y gestiona todos los io y eventos en el grupo de eventos. (en caso de libeio threadpool). Deberías consultar el tutorial de Ryan Dahl sobre libUv. Eso comenzará a tener más sentido para usted sobre cómo funciona libUv en sí mismo y luego comprenderá cómo funciona node.js en la parte superior de libuv y v8.
Para entender solo el bucle de eventos de JavaScript, debería considerar ver estos videos
Para ver cómo se usa libeio con node.js para crear módulos asíncronos, debería ver este ejemplo .
Básicamente, lo que sucede dentro de node.js es que el bucle v8 se ejecuta y maneja todas las partes de JavaScript, así como los módulos C ++ [cuando se ejecutan en un hilo principal (según la documentación oficial, node.js en sí es de un solo subproceso)]. Cuando está fuera del hilo principal, libev y libeio lo manejan en el grupo de hilos y libev proporciona la interacción con el bucle principal. Entonces, según tengo entendido, node.js tiene 1 bucle de eventos permanente: ese es el bucle de eventos v8. Para manejar las tareas asíncronas de C ++ está utilizando un conjunto de subprocesos [a través de libeio y libev].
Por ejemplo:
eio_custom(Task,FLAG,AfterTask,Eio_REQUEST);
Lo que aparece en todos los módulos suele llamar a la función Task
en el conjunto de subprocesos. Cuando está completo, llama a la AfterTask
función en el hilo principal. Mientras Eio_REQUEST
que el manejador de solicitudes puede ser una estructura / objeto cuyo motivo es proporcionar comunicación entre el conjunto de subprocesos y el subproceso principal.
process.nextTick
: en el siguiente bucle alrededor del bucle de eventos, llame a esta devolución de llamada. Este no es un simple alias para setTimeout (fn, 0), es mucho más eficiente. ¿A qué bucle de evento se refiere esto? V8 evento de bucle?Parece que algunas de las entidades discutidas (por ejemplo: libev, etc.) han perdido relevancia debido al hecho de que ha pasado un tiempo, pero creo que la pregunta aún tiene un gran potencial.
Permítanme tratar de explicar el funcionamiento del modelo basado en eventos con la ayuda de un ejemplo abstracto, en un entorno UNIX abstracto, en el contexto de Node, a partir de hoy.
Perspectiva del programa:
La maquinaria de eventos anterior se llama marco de bucle de eventos libuv AKA. Node aprovecha esta biblioteca para implementar su modelo de programación dirigida por eventos.
Perspectiva del nodo:
Si bien la mayoría de las funcionalidades se atienden de esta manera, algunas (versiones asíncronas) de las operaciones de archivo se llevan a cabo con la ayuda de hilos adicionales, bien integrados en el libuv. Si bien las operaciones de E / S de red pueden esperar a la espera de un evento externo, como el otro punto final que responde con datos, etc., las operaciones de archivo necesitan algo de trabajo del nodo mismo. Por ejemplo, si abre un archivo y espera que el fd esté listo con datos, no sucederá, ¡ya que nadie está leyendo realmente! Al mismo tiempo, si lee el archivo en línea en el hilo principal, puede bloquear otras actividades en el programa y puede causar problemas visibles, ya que las operaciones de archivo son muy lentas en comparación con las actividades vinculadas a la CPU. Por lo tanto, los subprocesos de trabajo internos (configurables a través de la variable de entorno UV_THREADPOOL_SIZE) se emplean para operar en archivos,
Espero que esto ayude.
fuente
Una introducción a libuv
También una imagen que describe el bucle de eventos en Node.js por @ BusyRich
Actualización 05/09/2017
Según este bucle de eventos del documento Node.js ,
El siguiente diagrama muestra una descripción general simplificada del orden de operaciones del bucle de eventos.
nota: cada cuadro se denominará "fase" del bucle de eventos.
Resumen de fases
setTimeout()
ysetInterval()
.setImmediate()
.setImmediate()
aquí se invocan las devoluciones de llamada.socket.on('close', ...)
.Entre cada ejecución del bucle de eventos, Node.js comprueba si está esperando alguna E / S asíncrona o temporizadores y se apaga limpiamente si no hay ninguno.
fuente
In the node-v0.9.0 version of libuv libev was removed
", pero no hay una descripción al respecto en nodejschangelog
. github.com/nodejs/node/blob/master/CHANGELOG.md . Y si se elimina libev, ¿cómo se realiza la E / S asíncrona en nodejs?Hay un bucle de eventos en la arquitectura NodeJs.
Modelo de bucle de eventos de Node.js
Las aplicaciones de nodo se ejecutan en un modelo controlado por eventos de subproceso único. Sin embargo, Node implementa un grupo de subprocesos en segundo plano para que se pueda realizar el trabajo.
Node.js agrega trabajo a una cola de eventos y luego tiene un solo hilo que ejecuta un bucle de eventos. El bucle de eventos toma el elemento superior en la cola de eventos, lo ejecuta y luego toma el siguiente elemento.
Cuando se ejecuta un código que tiene una vida más larga o que tiene E / S de bloqueo, en lugar de llamar a la función directamente, agrega la función a la cola de eventos junto con una devolución de llamada que se ejecutará una vez que se complete la función. Cuando todos los eventos en la cola de eventos Node.js se han ejecutado, la aplicación Node.js finaliza.
El bucle de eventos comienza a encontrar problemas cuando nuestras funciones de aplicación se bloquean en E / S.
Node.js utiliza devoluciones de llamada de eventos para evitar tener que esperar para bloquear E / S. Por lo tanto, cualquier solicitud que realice E / S de bloqueo se realiza en un subproceso diferente en segundo plano.
Cuando se recupera un evento que bloquea la E / S de la cola de eventos, Node.js recupera un subproceso del grupo de subprocesos y ejecuta la función allí en lugar del subproceso principal del bucle de eventos. Esto evita que la E / S de bloqueo retenga el resto de los eventos en la cola de eventos.
fuente
Solo hay un bucle de eventos proporcionado por libuv, V8 es solo un motor de tiempo de ejecución JS.
fuente
Como principiante de JavaScript, también tuve la misma duda: ¿NodeJS contiene 2 bucles de eventos? Después de una larga investigación y discusión con uno de los contribuyentes de V8, obtuve los siguientes conceptos.
fuente
La
pbkdf2
función tiene la implementación de JavaScript, pero en realidad delega todo el trabajo a realizar en el lado de C ++.recurso: https://github.com/nodejs/node/blob/master/src/node_crypto.cc
El módulo Libuv tiene otra responsabilidad que es relevante para algunas funciones muy particulares en la biblioteca estándar.
Para algunas llamadas de función de biblioteca estándar, el lado del Nodo C ++ y Libuv deciden hacer cálculos caros fuera del ciclo de eventos por completo.
En su lugar, hacen uso de algo llamado grupo de subprocesos, el grupo de subprocesos es una serie de cuatro subprocesos que se pueden usar para ejecutar tareas computacionalmente costosas como el
pbkdf2
función.Por defecto, Libuv crea 4 hilos en este grupo de hilos.
Además de los hilos utilizados en el bucle de eventos, hay otros cuatro hilos que pueden usarse para descargar cálculos costosos que deben ocurrir dentro de nuestra aplicación.
Muchas de las funciones incluidas en la biblioteca estándar de Nodos utilizan automáticamente este grupo de subprocesos. los
pbkdf2
función es una de ellas.La presencia de este grupo de subprocesos es muy significativa.
Por lo tanto, Node no es realmente un único subproceso, porque hay otros subprocesos que utiliza Node para realizar algunas tareas computacionalmente costosas.
Si el grupo de eventos fue responsable de realizar la tarea computacionalmente costosa, entonces nuestra aplicación Node no podría hacer nada más.
Nuestra CPU ejecuta todas las instrucciones dentro de un hilo una por una.
Al usar el grupo de subprocesos podemos hacer otras cosas dentro de un bucle de eventos mientras se realizan los cálculos.
fuente