¿Cuál sería mejor para tareas simultáneas en node.js? Fibras ¿Trabajadores web? o hilos?


111

Me topé con node.js hace algún tiempo y me gustó mucho. Pero pronto descubrí que carecía de la capacidad para realizar tareas intensivas en la CPU. Entonces, comencé a buscar en Google y obtuve estas respuestas para resolver el problema: Fibras, Webworkers e Threads (thread-a-gogo). Ahora, cuál usar es una confusión y definitivamente es necesario usar uno de ellos; después de todo, ¿cuál es el propósito de tener un servidor que sea bueno en IO y nada más? Sugerencias necesarias!

ACTUALIZAR:

Estaba pensando en un camino de retraso; solo necesito sugerencias al respecto. Ahora, lo que pensé fue esto: tengamos algunos hilos (usando thread_a_gogo o quizás webworkers). Ahora, cuando necesitemos más, podemos crear más. Pero habrá algún límite sobre el proceso de creación. (no implicado por el sistema, pero probablemente debido a la sobrecarga). Ahora, cuando superamos el límite, podemos bifurcar un nuevo nodo y comenzar a crear hilos sobre él. De esta manera, puede continuar hasta que alcancemos algún límite (después de todo, los procesos también tienen una gran sobrecarga). Cuando se alcanza este límite, comenzamos a poner en cola las tareas. Siempre que un hilo quede libre, se le asignará una nueva tarea. De esta manera, puede continuar sin problemas.

Entonces, eso fue lo que pensé. ¿Es buena esta idea? Soy un poco nuevo en todo este proceso e hilos, así que no tengo ninguna experiencia en ello. Comparta sus opiniones.

Gracias. :)


Tenga en cuenta: Los trabajadores son una especificación del navegador, no una función de Javascript.
FredTheWebGuy

Bueno, ya veo eso. Mi pregunta era sobre node.js: ¡el código del servidor y no sobre el lado del cliente!
Parth Thakkar

Solo una aclaración: veo que la pregunta original era sobre Webworkers en NodeJs, lo cual es imposible, NodeJs usa "Threads". Sin embargo, hay un módulo NodeJS flotando que permite la sintaxis de WebWorker dentro del tiempo de ejecución de NodeJs.
FredTheWebGuy

Respuestas:


330

Node tiene un paradigma completamente diferente y una vez que se captura correctamente, es más fácil ver esta forma diferente de resolver problemas. Nunca necesita múltiples subprocesos en una aplicación Node (1) porque tiene una forma diferente de hacer lo mismo. Creas múltiples procesos; pero es muy diferente a, por ejemplo, cómo funciona el mpm Prefork de Apache Web Server.

Por ahora, pensemos que solo tenemos un núcleo de CPU y desarrollaremos una aplicación (a la manera de Node) para hacer algo de trabajo. Nuestro trabajo consiste en procesar un archivo grande que se ejecuta en su contenido byte a byte. La mejor manera para nuestro software es comenzar el trabajo desde el principio del archivo, seguirlo byte a byte hasta el final.

- ¡¡Oye, Hasan, supongo que o eres un novato o eres muy viejo de la época de mi abuelo !!! ¿Por qué no creas algunos hilos y lo haces mucho más rápido?

- Oh, solo tenemos un núcleo de CPU.

-- ¿Y qué? Crea algunos hilos, ¡hazlo más rápido!

-- No funciona así. Si creo hilos, lo haré más lento. Porque agregaré mucha sobrecarga al sistema para cambiar entre subprocesos, tratando de darles una cantidad justa de tiempo, y dentro de mi proceso, tratando de comunicarse entre estos subprocesos. Además de todos estos hechos, también tendré que pensar en cómo dividiré un solo trabajo en múltiples partes que se pueden hacer en paralelo.

- Está bien, está bien, veo que eres pobre. Usemos mi computadora, ¡tiene 32 núcleos!

- Vaya, eres increíble mi querido amigo, muchas gracias. ¡Lo aprecio!

Luego volvemos al trabajo. Ahora tenemos 32 núcleos de CPU gracias a nuestro rico amigo. Las reglas que tenemos que cumplir acaban de cambiar. Ahora queremos utilizar toda esta riqueza que se nos da.

Para usar múltiples núcleos, necesitamos encontrar una manera de dividir nuestro trabajo en partes que podamos manejar en paralelo. Si no fuera Node, usaríamos subprocesos para esto; 32 subprocesos, uno para cada núcleo de CPU. Sin embargo, dado que tenemos Node, crearemos procesos de 32 Node.

Los subprocesos pueden ser una buena alternativa a los procesos de Node, tal vez incluso una mejor manera; pero solo en un tipo específico de trabajo donde el trabajo ya está definido y tenemos un control completo sobre cómo manejarlo. Aparte de esto, para cualquier otro tipo de problema en el que el trabajo proviene de afuera de una manera sobre la que no tenemos control y queremos responder lo más rápido posible, la forma de Node es indiscutiblemente superior.

- Oye, Hasan, ¿sigues trabajando con un solo hilo? ¿Qué te pasa, hombre? Te acabo de proporcionar lo que querías. Ya no tienes excusas. Crea hilos, haz que corra más rápido.

- He dividido el trabajo en piezas y cada proceso trabajará en una de estas piezas en paralelo.

- ¿Por qué no creas hilos?

- Lo siento, no creo que sea utilizable. ¿Puedes llevarte tu computadora si quieres?

- No, está bien, soy genial, simplemente no entiendo por qué no usas hilos.

- Gracias por la computadora. :) Ya dividí el trabajo en piezas y creo procesos para trabajar en estas piezas en paralelo. Todos los núcleos de la CPU se utilizarán por completo. Podría hacer esto con subprocesos en lugar de procesos; pero Node tiene esta manera y mi jefe Parth Thakkar quiere que use Node.

- De acuerdo, avíseme si necesita otra computadora. :pags

Si creo 33 procesos, en lugar de 32, el programador del sistema operativo pausará un hilo, iniciará el otro, lo pausará después de algunos ciclos, iniciará el otro de nuevo ... Esto es una sobrecarga innecesaria. No lo quiero. De hecho, en un sistema con 32 núcleos, ni siquiera quisiera crear exactamente 32 procesos, 31 pueden ser mejores . Porque no es solo mi aplicación la que funcionará en este sistema. Dejar un poco de espacio para otras cosas puede ser bueno, sobre todo si tenemos 32 habitaciones.

Creo que ahora estamos en la misma página acerca de la utilización completa de procesadores para tareas intensivas en CPU .

- Hmm, Hasan, lamento burlarme un poco de ti. Creo que ahora te entiendo mejor. Pero todavía hay algo para lo que necesito una explicación: ¿Qué es todo el rumor acerca de ejecutar cientos de subprocesos? Leí en todas partes que los hilos son mucho más rápidos de crear y tontos que los procesos de bifurcación. Usted bifurca procesos en lugar de subprocesos y cree que es lo más alto que obtendría con Node. Entonces, ¿Node no es apropiado para este tipo de trabajo?

- No te preocupes, yo también soy genial. Todo el mundo dice estas cosas, así que creo que estoy acostumbrado a escucharlas.

-- ¿Entonces? ¿El nodo no es bueno para esto?

- Node es perfectamente bueno para esto, aunque los subprocesos también pueden ser buenos. En cuanto a la sobrecarga de creación de subprocesos / procesos; en las cosas que repites mucho, cada milisegundo cuenta. Sin embargo, creo solo 32 procesos y tomará una pequeña cantidad de tiempo. Sucederá solo una vez. No hará ninguna diferencia.

- ¿Cuándo quiero crear miles de hilos, entonces?

- Nunca querrás crear miles de hilos. Sin embargo, en un sistema que está realizando un trabajo que proviene del exterior, como un servidor web que procesa solicitudes HTTP; si está utilizando un hilo para cada solicitud, creará muchos hilos, muchos de ellos.

- ¿Pero el nodo es diferente? ¿Correcto?

-- Sí exactamente. Aquí es donde Node realmente brilla. Como un hilo es mucho más ligero que un proceso, una llamada a función es mucho más ligera que un hilo. El nodo llama a funciones, en lugar de crear subprocesos. En el ejemplo de un servidor web, cada solicitud entrante provoca una llamada de función.

-- Mmmm interesante; pero solo puede ejecutar una función al mismo tiempo si no está utilizando varios subprocesos. ¿Cómo puede funcionar esto cuando llegan muchas solicitudes al servidor web al mismo tiempo?

- Tiene toda la razón sobre cómo se ejecutan las funciones, una a la vez, nunca dos en paralelo. Quiero decir, en un solo proceso, solo se ejecuta un alcance de código a la vez. El Programador del SO no viene y pausa esta función y cambia a otra, a menos que pause el proceso para dar tiempo a otro proceso, no a otro hilo de nuestro proceso. (2)

- Entonces, ¿cómo puede un proceso manejar 2 solicitudes a la vez?

- Un proceso puede manejar decenas de miles de solicitudes a la vez siempre que nuestro sistema tenga suficientes recursos (RAM, red, etc.). La forma en que se ejecutan esas funciones es LA DIFERENCIA CLAVE.

- Hmm, ¿debería estar emocionado ahora?

- Quizás :) El nodo ejecuta un bucle sobre una cola. En esta cola están nuestros trabajos, es decir, las llamadas que comenzamos a procesar las solicitudes entrantes. El punto más importante aquí es la forma en que diseñamos nuestras funciones para que se ejecuten. En lugar de comenzar a procesar una solicitud y hacer que la persona que llama espere hasta que terminemos el trabajo, finalizamos rápidamente nuestra función después de realizar una cantidad aceptable de trabajo. Cuando llegamos a un punto en el que necesitamos esperar a que otro componente haga algún trabajo y nos devuelva un valor, en lugar de esperar eso, simplemente terminamos nuestra función agregando el resto del trabajo a la cola.

- ¿Suena demasiado complejo?

- No, no, puedo sonar complejo; pero el sistema en sí es muy simple y tiene perfecto sentido.

Ahora quiero dejar de citar el diálogo entre estos dos desarrolladores y terminar mi respuesta después de un último ejemplo rápido de cómo funcionan estas funciones.

De esta manera, estamos haciendo lo que normalmente haría OS Scheduler. Pausamos nuestro trabajo en algún momento y dejamos que se ejecuten otras llamadas a funciones (como otros subprocesos en un entorno de subprocesos múltiples) hasta que tengamos nuestro turno nuevamente. Esto es mucho mejor que dejar el trabajo a OS Scheduler, que intenta dar el tiempo justo a cada hilo del sistema. Sabemos lo que estamos haciendo mucho mejor que OS Scheduler y se espera que nos detengamos cuando deberíamos detenernos.

A continuación se muestra un ejemplo simple en el que abrimos un archivo y lo leemos para trabajar un poco con los datos.

Manera sincrónica:

Open File
Repeat This:    
    Read Some
    Do the work

Manera asincrónica:

Open File and Do this when it is ready: // Our function returns
    Repeat this:
        Read Some and when it is ready: // Returns again
            Do some work

Como ves, nuestra función pide al sistema que abra un archivo y no espera a que se abra. Termina por sí solo proporcionando los siguientes pasos después de que el archivo esté listo. Cuando regresamos, Node ejecuta otras llamadas a funciones en la cola. Después de ejecutar todas las funciones, el bucle de eventos pasa al siguiente turno ...

En resumen, Node tiene un paradigma completamente diferente al del desarrollo multiproceso; pero esto no quiere decir que le falten cosas. Para un trabajo sincrónico (donde podemos decidir el orden y la forma de procesamiento), funciona tan bien como el paralelismo multiproceso. Para un trabajo que proviene del exterior, como solicitudes a un servidor, simplemente es superior.


(1) A menos que esté creando bibliotecas en otros lenguajes como C / C ++, en cuyo caso aún no crea subprocesos para dividir trabajos. Para este tipo de trabajo, tiene dos hilos, uno de los cuales continuará la comunicación con Node mientras que el otro hace el trabajo real.

(2) De hecho, cada proceso de nodo tiene varios subprocesos por las mismas razones que mencioné en la primera nota al pie. Sin embargo, esto no es como 1000 hilos haciendo trabajos similares. Esos subprocesos adicionales son para cosas como aceptar eventos de E / S y manejar mensajes entre procesos.

ACTUALIZAR (Como respuesta a una buena pregunta en los comentarios)

@Mark, gracias por la crítica constructiva. En el paradigma de Node, nunca debe tener funciones que tarden demasiado en procesarse, a menos que todas las demás llamadas en la cola estén diseñadas para ejecutarse una tras otra. En el caso de tareas computacionalmente costosas, si miramos la imagen en su totalidad, vemos que esto no es una cuestión de "¿Deberíamos usar hilos o procesos?" pero una pregunta de "¿Cómo podemos dividir estas tareas de una manera bien equilibrada en subtareas para poder ejecutarlas en paralelo empleando múltiples núcleos de CPU en el sistema?" Digamos que procesaremos 400 archivos de video en un sistema con 8 núcleos. Si queremos procesar un archivo a la vez, entonces necesitamos un sistema que procese diferentes partes del mismo archivo, en cuyo caso, tal vez, un sistema multiproceso de un solo proceso será más fácil de construir e incluso más eficiente. Todavía podemos usar Node para esto ejecutando múltiples procesos y pasando mensajes entre ellos cuando sea necesario compartir el estado / comunicación. Como dije antes, un enfoque multiproceso con Node esasí como un enfoque multiproceso en este tipo de tareas; pero no más que eso. Nuevamente, como dije antes, la situación en la que Node brilla es cuando tenemos estas tareas como entrada al sistema desde múltiples fuentes, ya que mantener muchas conexiones al mismo tiempo es mucho más liviano en Node en comparación con un hilo por conexión o un proceso por conexión. sistema.

En cuanto a setTimeout(...,0)llamadas; a veces, puede ser necesario dar un descanso durante una tarea que requiere mucho tiempo para permitir que las llamadas en la cola tengan su parte de procesamiento. Dividir las tareas de diferentes maneras puede evitarlo; pero aún así, esto no es realmente un truco, es solo la forma en que funcionan las colas de eventos. Además, usar process.nextTickpara este fin es mucho mejor ya que cuando lo uses setTimeout, será necesario calcular y verificar el tiempo transcurrido mientras que process.nextTickes simplemente lo que realmente queremos: "Oye tarea, vuelve al final de la cola, ¡has usado tu parte! "


9
¡Asombroso! ¡Increíble! ¡Me encantó la forma en que respondiste esta pregunta! :)
Parth Thakkar

48
Claro :) ¡Realmente no puedo creer que haya personas extremadamente malas que voten en contra de este artículo de respuesta! El interlocutor lo llama "¡Increíble!" y el autor de un libro me ofrece escribir en su sitio web después de ver esto; pero algunos genios lo votan en contra. ¿Por qué no comparte su brillante cualidad intelectual y comenta sobre ella en lugar de votar en forma mezquina y disimulada, eh? ¿Por qué algo bueno te molesta tanto? ¿Por qué quiere evitar que algo útil llegue a otras personas que realmente se pueden beneficiar de ello?
hasanyasin

9
Esta no es una respuesta completamente justa. ¿Qué pasa con las tareas computacionalmente costosas, donde no podemos "finalizar rápidamente" nuestra llamada de función? Creo que algunas personas usan algunos setTimeout(...,0)trucos para esto, pero ¿usar un hilo separado en este escenario seguramente sería mejor?
mpen

3
@hasanyasin ¡Esta es la mejor explicación sobre el nodo que encontré hasta ahora! :)
Venemo

7
@Mark Generalmente, si es tan costoso desde el punto de vista computacional, hay opciones / módulos para trabajadores de proceso / banda de rodadura ... En general, para este tipo de cosas, uso una cola de mensajes y tengo procesos de trabajo que manejan una tarea en un tiempo de la cola y trabajar en esa tarea. Esto también permite escalar a varios servidores. En este sentido, Substack tiene una gran cantidad de módulos dirigidos al aprovisionamiento y escalado que puede ver.
Tracker1

34

(Actualización 2016: los trabajadores web van a io.js, una bifurcación de Node.js, Node.js v7, ver más abajo)

(Actualización 2017: los trabajadores web no van a Node.js v7 o v8; consulte a continuación).

(2018 Actualizar: Web trabajadores se van a v10.5.0 Node.js Nodo - ver más abajo).

Alguna aclaración

Después de leer las respuestas anteriores, me gustaría señalar que no hay nada en los trabajadores web que esté en contra de la filosofía de JavaScript en general y Node en particular con respecto a la concurrencia. (Si lo hubiera, ni siquiera sería discutido por el WHATWG, y mucho menos implementado en los navegadores).

Puede pensar en un trabajador web como un microservicio ligero al que se accede de forma asincrónica. No se comparte ningún estado. No existen problemas de bloqueo. No hay bloqueo. No se necesita sincronización. Al igual que cuando usa un servicio RESTful de su programa Node, no se preocupa de que ahora sea "multiproceso" porque el servicio RESTful no está en el mismo hilo que su propio bucle de eventos. Es solo un servicio separado al que accede de forma asincrónica y eso es lo que importa.

Lo mismo ocurre con los trabajadores web. Es solo una API para comunicarse con el código que se ejecuta en un contexto completamente separado y si está en un hilo diferente, un proceso diferente, un grupo diferente, una zona, un contenedor o una máquina diferente es completamente irrelevante, debido a una API estrictamente asincrónica y sin bloqueo. con todos los datos pasados ​​por valor.

De hecho, los trabajadores web son conceptualmente perfectos para Node que, como muchas personas no saben, utiliza de manera incidental los subprocesos en gran medida y, de hecho, "todo se ejecuta en paralelo, excepto su código", consulte:

Pero los trabajadores web ni siquiera necesitan implementarse mediante subprocesos. Puede utilizar procesos, subprocesos ecológicos o incluso servicios RESTful en la nube, siempre que se utilice la API del trabajador web. Toda la belleza de la API de transmisión de mensajes con semántica de llamada por valor es que la implementación subyacente es prácticamente irrelevante, ya que los detalles del modelo de concurrencia no se expondrán.

Un bucle de eventos de un solo hilo es perfecto para operaciones vinculadas a E / S. No funciona tan bien para operaciones vinculadas a la CPU, especialmente las de ejecución prolongada. Para eso, necesitamos generar más procesos o usar subprocesos. La gestión de procesos secundarios y la comunicación entre procesos de forma portátil puede ser bastante difícil y, a menudo, se considera una exageración para tareas simples, mientras que el uso de subprocesos significa lidiar con bloqueos y problemas de sincronización que son muy difíciles de hacer bien.

Lo que a menudo se recomienda es dividir las operaciones vinculadas a la CPU de larga ejecución en tareas más pequeñas (algo como el ejemplo en la sección "Respuesta original" de mi respuesta a Acelerar setInterval ) pero no siempre es práctico y no usa más de un núcleo de CPU.

Lo escribo para aclarar los comentarios que básicamente decían que los trabajadores web se crearon para navegadores, no para servidores (olvidando que se puede decir sobre casi todo en JavaScript).

Módulos de nodo

Hay algunos módulos que se supone que agregan trabajadores web al nodo:

No he usado ninguno de ellos, pero tengo dos observaciones rápidas que pueden ser relevantes: en marzo de 2015, node-webworker se actualizó por última vez hace 4 años y node-webworker-threads se actualizó por última vez hace un mes. También veo en el ejemplo de uso de node-webworker-threads que puede usar una función en lugar de un nombre de archivo como argumento para el constructor Worker que parece que puede causar problemas sutiles si se implementa usando hilos que comparten memoria (a menos que el functions se usa solo para su método .toString () y, de lo contrario, se compila en un entorno diferente, en cuyo caso puede estar bien; tengo que analizarlo más profundamente, solo compartiendo mis observaciones aquí).

Si hay algún otro proyecto relevante que implemente la API de trabajadores web en Node, deje un comentario.

Actualización 1

No sabía que aún en el momento de la escritura, pero por cierto un día antes de que escribí esta respuesta Web trabajadores se añadieron a io.js .

( io.js es una bifurcación de Node.js; consulte: Por qué io.js decidió bifurcar Node.js , una entrevista de InfoWorld con Mikeal Rogers, para obtener más información).

No solo prueba el punto de que no hay nada en los trabajadores web que esté en contra de la filosofía de JavaScript en general y de Node en particular con respecto a la concurrencia, sino que puede resultar en que los trabajadores web sean ciudadanos de primera clase en JavaScript del lado del servidor como io. js (y posiblemente Node.js en el futuro) tal como ya está en JavaScript del lado del cliente en todos los navegadores modernos .

Actualización 2

En la Actualización 1 y en mi tweet, me refería a la solicitud de extracción de io.js # 1159 que ahora redirige al Nodo PR # 1159 que se cerró el 8 de julio y se reemplazó con el Nodo PR # 2133 , que aún está abierto. Se está llevando a cabo una discusión bajo esas solicitudes de extracción que pueden proporcionar información más actualizada sobre el estado de los trabajadores web en io.js / Node.js.

Actualización 3

Información más reciente : gracias a NiCk Newman por publicarlo en los comentarios: Ahí están los trabajadores: compromiso de implementación inicial de Petka Antonov del 6 de septiembre de 2015 que se puede descargar y probar en este árbol . Ver comentarios de NiCk Newman para más detalles.

Actualización 4

A mayo de 2016, los últimos comentarios sobre el PR # 2133 aún abierto - trabajadores: la implementación inicial tenía 3 meses de antigüedad. El 30 de mayo, Matheus Moreira me pidió que publicara una actualización de esta respuesta en los comentarios a continuación y preguntó por el estado actual de esta función en los comentarios de relaciones públicas.

Las primeras respuestas en la discusión de relaciones públicas fueron escépticas, pero luego Ben Noordhuis escribió que "Lograr que esto se fusione en una forma u otra está en mi lista de tareas pendientes para la v7".

Todos los demás comentarios parecían respaldar eso y, a partir de julio de 2016, parece que los Web Workers deberían estar disponibles en la próxima versión de Node , la versión 7.0 que se planea lanzar en octubre de 2016 (no necesariamente en la forma de este PR exacto).

Gracias a Matheus Moreira por señalarlo en los comentarios y revivir la discusión en GitHub.

Actualización 5

En julio de 2016, hay pocos módulos en npm que no estaban disponibles antes; para obtener una lista completa de los módulos relevantes, busque npm para trabajadores, trabajadores web, etc. Si algo en particular funciona o no para usted, publique un comentario.

Actualización 6

A partir de enero de 2017 , es poco probable que los trabajadores web se fusionen con Node.js.

La solicitud de extracción # 2133 trabajadores: la implementación inicial de Petka Antonov desde el 8 de julio de 2015 fue finalmente cerrada por Ben Noordhuis el 11 de diciembre de 2016, quien comentó que "el soporte de subprocesos múltiples agrega demasiados modos de falla nuevos para un beneficio insuficiente" y "nosotros también puede lograrlo utilizando medios más tradicionales como la memoria compartida y una serialización más eficiente ".

Para obtener más información, consulte los comentarios al PR 2133 en GitHub.

Gracias nuevamente a Matheus Moreira por señalarlo en los comentarios.

Actualización 6

Me complace anunciar que hace unos días, en junio de 2018, los trabajadores web aparecieron en Node v10.5.0 como una función experimental activada con la --experimental-workerbandera.

Para obtener más información, consulte:

🎉🎉🎉 ¡Por fin! Puedo hacer la séptima actualización de mi respuesta de Stack Overflow de 3 años, donde sostengo que enhebrar a los trabajadores web no va en contra de la filosofía de Node, ¡solo que esta vez digo que finalmente lo conseguimos! 😜👍


1
@NiCkNewman Gracias. Veo que la solicitud de extracción original en io.js está cerrada ahora y reemplazada por otra; con algo de discusión en los comentarios de las solicitudes de extracción en GitHub, tal vez pueda encontrar información allí. Ver: Actualización 2 en mi respuesta.
rsp

1
Sí, parece que acaba de solucionar el último problema de libuv. Me pregunto cuándo podré poner mis manos en el módulo. ¡No puedo esperar! Gracias por mantenernos actualizados ~ Edición: Acabo de inicializar: github.com/petkaantonov/io.js/commit/… ¡ Ahí vamos, ya viene!
NiCk Newman

1
Sí, está en vivo. (Aún no implementado oficialmente) pero puede descargar la fuente aquí: github.com/petkaantonov/io.js/tree/… ¡ y compilar si desea probarlo! Lo estoy haciendo ahora ~
NiCk Newman

1
@NiCkNewman Gracias por la nueva información, la agregué a la respuesta.
rsp

1
¿Puede actualizarnos sobre el estado de la workersimplementación de Node.js ? Los últimos comentarios en PR # 2133 son de febrero; los desarrolladores aparentemente se encontraron con un problema y no hay comentarios que indiquen que se ha resuelto.
Matheus Moreira

8

Vengo de la vieja escuela de pensamiento donde usamos multi-threading para hacer que el software sea rápido. Durante los últimos 3 años he estado usando Node.js y soy un gran partidario de él. Como hasanyasin explicó en detalle cómo funciona el nodo y el concepto de funcionalidad asincrónica. Pero permítanme agregar algunas cosas aquí.

En los viejos tiempos, con núcleos únicos y velocidades de reloj más bajas, probamos varias formas de hacer que el software funcione rápido y en paralelo. en los días de DOS, solíamos ejecutar un programa a la vez. Entonces en Windows comenzamos a ejecutar múltiples aplicaciones (procesos) juntos. Se probaron conceptos como preventivo y no preventivo (o cooperativo). ahora sabemos que preventiva era la respuesta para una mejor tarea de procesamiento múltiple en computadoras de un solo núcleo. Llegaron los conceptos de procesos / tareas y cambio de contexto. Que el concepto de hilo para reducir aún más la carga del cambio de contexto de proceso. El hilo se acuñó como una alternativa liviana para generar nuevos procesos.

Así que me guste o no, subproceso de señal o no de múltiples núcleos o de un solo núcleo, sus procesos serán reemplazados y cortados en tiempo por el sistema operativo.

Nodejs es un proceso único y proporciona un mecanismo asíncrono. Aquí, los trabajos se envían al sistema operativo subyacente para realizar tareas mientras esperamos en un ciclo de eventos a que finalice la tarea. Una vez que recibimos una señal verde del sistema operativo, realizamos lo que sea necesario. Ahora, en cierto modo, esto es multitarea cooperativa / no preventiva, por lo que nunca deberíamos bloquear el bucle de eventos durante un período de tiempo muy largo, de lo contrario, degradaremos nuestra aplicación muy rápido.
Entonces, si alguna vez hay una tarea que es de naturaleza bloqueante o que consume mucho tiempo, tendremos que diversificarla al mundo preventivo de sistemas operativos y subprocesos. hay buenos ejemplos de esto en la documentación de libuv . Además, si usted lee la información adicional que encuentre que FileI / S se maneja en las discusiones en Node.js .

Entonces, en primer lugar, todo está en el diseño de nuestro software. En segundo lugar, el cambio de contexto siempre ocurre sin importar lo que le digan. Los hilos están ahí y siguen ahí por una razón, la razón es que son más rápidos para cambiar entre procesos.

Bajo el capó en node.js es todo c ++ e hilos. Y node proporciona una forma de C ++ para extender su funcionalidad y acelerar aún más mediante el uso de subprocesos donde son imprescindibles, es decir, bloqueando tareas como leer desde una fuente escribiendo en una fuente, análisis de datos grandes, etc.

Sé que la respuesta de hasanyasin es la aceptada, pero para mí los hilos existirán sin importar lo que digas o cómo los ocultes detrás de los scripts, en segundo lugar, nadie solo interrumpe las cosas en los hilos solo por velocidad, se hace principalmente para bloquear tareas. Y los subprocesos están en la columna vertebral de Node.js, por lo que antes de atacar por completo, el subproceso múltiple está correcto. Además, los subprocesos son diferentes de los procesos y la limitación de tener procesos de nodo por núcleo no se aplica exactamente a la cantidad de subprocesos, los subprocesos son como subtareas de un proceso. de hecho, los hilos no aparecerán en el administrador de tareas de Windows o en el comando superior de Linux. una vez más son más de poco peso que los procesos


El código asincrónico no es una gran innovación (de hecho lo hemos tenido durante décadas) y el multiproceso no es una tecnología obsoleta que deba reemplazarse. Son herramientas diferentes con diferentes compensaciones y, de hecho, incluso se pueden combinar bastante bien. Cada vez que ejecuta node-cluster, de hecho ejecuta múltiples "subprocesos" (procesos en este caso, pero se podría lograr lo mismo con subprocesos, y ser aún más liviano). O tome Erlang o Go, que puede ejecutar miles de hilos verdes ...
Hejazzman

Creo que el punto principal que nos falta es que el proceso bajo el sistema operativo siempre se realizará de manera preventiva para brindar justicia. Además, con los procesadores múltiples puede tener una ejecución real de código paralelo, pero incluso entonces tendrá preferencia. El sistema operativo también realiza el trabajo asincrónico en algunos de los procesos.
Limplash

4

No estoy seguro de si los webworkers son relevantes en este caso, son tecnología del lado del cliente (se ejecutan en el navegador), mientras que node.js se ejecuta en el servidor. Las fibras, por lo que tengo entendido, también están bloqueando, es decir, son multitareas voluntarias, por lo que podría usarlas, pero debe administrar los cambios de contexto usted mismo a través de yield. Los subprocesos pueden ser en realidad lo que necesitas, pero no sé qué tan maduros son en node.js.


3
solo para su información, los webworkers se han adaptado (parcialmente) en node.js. Y están disponibles como node-workerspaquete. Eche un vistazo a esto: github.com/cramforce/node-worker
Parth Thakkar

Es bueno saberlo, gracias. Sin embargo, los documentos son muy escasos, no tengo idea de si se ejecuta en un hilo, proceso separado o simplemente se ejecuta en el mismo proceso, y no tengo tiempo para profundizar en el código, por lo que no tengo idea de si lo hará. trabaja para tu caso.
Lanzz

@ParthThakkar: Ese proyecto no se ha tocado en 3 años (2 cuando publicaste), y no ha pasado de 0.0.1.
mpen

@Mark: La razón de mi ignorancia al respecto es que todavía no soy un programador profesional. Diablos, ni siquiera estoy en una universidad. Todavía soy un becario de la escuela secundaria, que sigue leyendo sobre programación, además de administrar el trabajo escolar. Por lo tanto, no es ni remotamente posible para mí tener conocimiento sobre todos estos temas. Acabo de publicar lo que sabía ...
Parth Thakkar

@Mark: Aunque fue amable de tu parte señalar eso sobre la historia del proyecto. ¡¡Tales cosas serán atendidas en mis futuras respuestas !! :)
Parth Thakkar

3

worker_threadsse ha implementado y enviado detrás de una bandera en formato node@10.5.0. Todavía es una implementación inicial y se necesitan más esfuerzos para que sea más eficiente en versiones futuras. Vale la pena intentarlo a última hora node.


2

En opinión de muchos desarrolladores de Node, una de las mejores partes de Node es en realidad su naturaleza de un solo subproceso. Los subprocesos introducen una gran cantidad de dificultades con los recursos compartidos que Node evita por completo al no hacer nada más que IO sin bloqueo.

Eso no quiere decir que Node esté limitado a un solo hilo. Es solo que el método para obtener la concurrencia de subprocesos es diferente de lo que está buscando. La forma estándar de tratar los subprocesos es con el módulo de clúster que viene de serie con Node. Es un enfoque más simple para los subprocesos que tratarlos manualmente en su código.

Para tratar con programación asincrónica en su código (como en, evitar pirámides de devolución de llamada anidadas), el componente [Futuro] en la biblioteca Fibers es una opción decente. También le sugiero que consulte Asyncblock, que se basa en Fibers. Las fibras son agradables porque le permiten ocultar la devolución de llamada duplicando la pila y luego saltando entre pilas en un solo hilo según sea necesario. Le ahorra la molestia de los hilos reales al mismo tiempo que le brinda los beneficios. La desventaja es que los rastros de pila pueden volverse un poco raros cuando se usan fibras, pero no son tan malos.

Si no necesita preocuparse por las cosas asincrónicas y está más interesado en hacer mucho procesamiento sin bloquear, una simple llamada a process.nextTick (devolución de llamada) de vez en cuando es todo lo que necesita.


Bueno, tu sugerencia - acerca de los clusters - fue en lo que pensé inicialmente. Pero el problema con eso es su sobrecarga: se debe inicializar una nueva instancia de v8 cada vez que se bifurca un nuevo proceso (~ 30ms, 10MB). Entonces, no puede crear muchos de ellos. Esto se toma directamente de los documentos del nodo: estos nodos secundarios (sobre child_processes) siguen siendo instancias completamente nuevas de V8. Suponga al menos 30 ms de inicio y 10 MB de memoria para cada nodo nuevo. Es decir, no puede crear muchos miles de ellos.
Parth Thakkar

1
Ésta es exactamente la idea de cluster. Ejecuta un trabajador por núcleo de CPU. Lo más probable es que sea innecesario. Incluso las tareas intensivas en CPU funcionarán bien con un estilo asincrónico. Sin embargo, si realmente necesita subprocesos completos, probablemente debería considerar pasar a otro servidor backend por completo.
genericdave

1

Tal vez sería útil contar con más información sobre las tareas que está realizando. ¿Por qué necesitaría (como mencionó en su comentario a la respuesta de genericdave) crear muchos miles de ellos? La forma habitual de hacer este tipo de cosas en Node es iniciar un proceso de trabajo (utilizando un fork o algún otro método) que siempre se ejecuta y se puede comunicar mediante mensajes. En otras palabras, no inicie un nuevo trabajador cada vez que necesite realizar cualquier tarea que esté haciendo, simplemente envíe un mensaje al trabajador que ya está en ejecución y obtenga una respuesta cuando haya terminado. Honestamente, tampoco veo que iniciar muchos miles de subprocesos reales sea muy eficiente, todavía estás limitado por tus CPU.

Ahora, después de decir todo eso, he estado trabajando mucho con Hook.io últimamente, lo que parece funcionar muy bien para este tipo de tareas de descarga en otros procesos, tal vez pueda lograr lo que necesita.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.