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

Tropecé con node.js en algún momento y me gustó mucho. Pero pronto descubrí que carecía de la capacidad de realizar tareas intensivas de CPU. Entonces, comencé a buscar en Google y obtuve estas respuestas para resolver el problema: Fibras, Webworkers y Threads (thread-a-gogo). Ahora cuál usar es una confusión y uno de ellos definitivamente necesita ser utilizado, 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 una forma no tardía; solo necesitando sugerencias sobre eso. Ahora, lo que pensé fue esto: tengamos algunos hilos (usando thread_a_gogo o quizás webworkers). Ahora, cuando necesitamos más de ellos, 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 scopemos algún límite (después de todo, los procesos también tienen un gran costo). Cuando se alcanza este límite, comenzamos las tareas de puesta en cola. Siempre que un hilo se libere, se le asignará una nueva tarea. De esta manera, puede continuar sin problemas.

Entonces, eso fue lo que pensé. ¿Esta idea es buena? Soy un poco nuevo en todo este proceso e hilo de cosas, por lo que no tengo ninguna experiencia en ello. Por favor comparta sus opiniones

Gracias. 🙂

Nodo 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 hilos en una aplicación de nodo (1) porque tiene una forma diferente de hacer lo mismo. Usted crea múltiples procesos; pero es muy diferente de, por ejemplo, cómo funciona Prefork mpm de Apache Web Server.

Por ahora, pensemos que solo tenemos un núcleo de CPU y desarrollaremos una aplicación (en forma de Node) para hacer algo de trabajo. Nuestro trabajo es procesar un archivo grande que se ejecuta sobre su contenido byte por 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 eres un novato o una escuela muy vieja 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 hombre, hazlo más rápido!

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

– De acuerdo, bien, veo que eres pobre. Usemos mi computadora, ¡tiene 32 núcleos!

– Wow, 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 debemos respetar han cambiado. Ahora queremos utilizar toda esta riqueza que recibimos.

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

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

– Oye, Hasan, ¿sigues trabajando con un solo hilo? ¿Qué pasa contigo, hombre? Te acabo de proporcionar lo que querías. Ya no tienes excusas. Cree hilos, hágalo correr más rápido.

– He dividido el trabajo en pedazos y cada proceso funcionará en una de estas piezas en paralelo.

– ¿Por qué no creas hilos?

– Lo siento, no creo que sea utilizable. Puedes llevar tu computadora si quieres?

– No está bien, estoy bien, simplemente no entiendo por qué no usas hilos?

– Gracias por la computadora. 🙂 Ya dividí el trabajo en pedazos 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 hilos en lugar de procesos; pero Node tiene este camino y mi jefe, Parth Thakkar, quiere que use Nodo.

– De acuerdo, avísame si necesitas otra computadora. :pag

Si creo 33 procesos, en lugar de 32, el progtwigdor del sistema operativo pausará un hilo, iniciará el otro, lo parará después de algunos ciclos, iniciará el otro nuevamente … 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 más agradables . Porque no es solo mi aplicación la que funcionará en este sistema. Dejar un poco de espacio para otras cosas puede ser bueno, especialmente si tenemos 32 habitaciones.

Creo que ahora estamos en la misma línea sobre la utilización total de procesadores para tareas intensivas de CPU .

– Hmm, Hasan, lo siento por burlarte un poco. Creo que te entiendo mejor ahora. Pero todavía hay algo por lo que necesito una explicación: ¿qué es todo el rumor acerca de ejecutar cientos de hilos? Leo en todas partes que los hilos son mucho más rápidos de crear y tontos que los procesos de bifurcación. Tenedor procesos en lugar de hilos y crees que es lo más alto que obtendría con Nodo. Entonces, ¿el Nodo 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.

— ¿Asi que? Nodo no es bueno para esto?

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

– Cuando quiero crear miles de hilos, entonces?

– Nunca quieres crear miles de hilos. Sin embargo, en un sistema que está haciendo 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.

– Nodo es diferente, sin embargo? ¿Derecha?

— Sí exactamente. Aquí es donde realmente brilla Nodo. Al igual que un hilo es mucho más ligero que un proceso, una llamada de 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 causa una llamada de función.

— Mmm interesante; pero solo puede ejecutar una función al mismo tiempo si no está utilizando múltiples hilos. ¿Cómo puede funcionar esto cuando muchas solicitudes llegan al servidor web al mismo tiempo?

– Tiene toda la razón sobre cómo funcionan las funciones, una a la vez, nunca dos en paralelo. Quiero decir en un solo proceso, solo se ejecuta un scope de código a la vez. El Progtwigdor del sistema operativo 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 en 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.). Cómo se ejecutan esas funciones es LA DIFERENCIA DE LA LLAVE.

– Hmm, ¿debería estar emocionado ahora?

– Tal vez 🙂 Node ejecuta un ciclo 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 ejecutar. En lugar de comenzar a procesar una solicitud y hacer que la persona que llama espere hasta que terminemos el trabajo, rápidamente finalizamos nuestra función después de hacer una cantidad aceptable de trabajo. Cuando llegamos a un punto en el que tenemos que esperar a que otro componente haga algún trabajo y nos devuelva un valor, en lugar de esperar eso, simplemente terminamos nuestra función y agregamos el rest del trabajo a la cola.

– Suena demasiado complejo?

– No, no, podría sonar complejo; pero el sistema en sí es muy simple y tiene mucho 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 forma, estamos haciendo lo que el Progtwigdor de SO normalmente haría. Pausamos nuestro trabajo en algún momento y permitimos que otras llamadas a funciones (como otros hilos en un entorno de subprocesos múltiples) se ejecuten hasta que lleguemos a nuestro turno nuevamente. Esto es mucho mejor que dejar el trabajo en OS Scheduler, que intenta dar tiempo justo a cada hilo en el sistema. Sabemos lo que estamos haciendo mucho mejor que el Progtwigdor de sistema operativo y se espera que detengamos cuando debamos detenerlo.

A continuación se muestra un ejemplo simple en el que abrimos un archivo y lo leímos para hacer algún trabajo sobre 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 puede ver, nuestra función le pide al sistema que abra un archivo y no espera a que se abra. Se termina proporcionando los siguientes pasos después de que el archivo esté listo. Cuando volvemos, Node ejecuta otras llamadas a función en la cola. Después de ejecutar todas las funciones, el ciclo de eventos se mueve al siguiente turno …

En resumen, Nodo tiene un paradigma completamente diferente que el desarrollo de subprocesos múltiples; pero esto no significa que le falten cosas. Para un trabajo sincrónico (donde podemos decidir el orden y el modo de procesamiento), funciona tan bien como el paralelismo de subprocesos múltiples. Para un trabajo que viene de fuera 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 múltiples hilos por las mismas razones que mencioné en la primera nota al pie. Sin embargo, esto no es como 1000 hilos haciendo trabajos similares. Esos hilos adicionales son para cosas como aceptar eventos IO y manejar mensajes entre procesos.

ACTUALIZACIÓN (Como respuesta a una buena pregunta en 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 detrás de otra. En el caso de tareas computacionalmente costosas, si miramos la imagen completa, vemos que no se trata de “¿Deberíamos usar hilos o procesos?” pero una pregunta de “¿cómo podemos dividir estas tareas de una manera equilibrada en subtareas que podemos ejecutar 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 de un solo proceso multiproceso será más fácil de construir y aún más eficiente. Todavía podemos usar el Nodo para esto al ejecutar múltiples procesos y pasar mensajes entre ellos cuando se necesita el estado compartido / comunicación. Como dije antes, un enfoque de procesos múltiples con Node es tan bien como un enfoque de múltiples subprocesos en este tipo de tareas; pero no más que eso. De nuevo, como dije antes, la situación en la que Node brilla es cuando tenemos estas tareas como entrada al sistema desde múltiples fonts, ya que mantener muchas conexiones al mismo tiempo es mucho más ligero en Node comparado con un hilo por conexión o proceso por conexión sistema.

En cuanto a las setTimeout(...,0) ; A veces, dar un descanso durante una tarea que consume tiempo para permitir llamadas en la cola puede ser necesaria. Dividir tareas de diferentes maneras puede salvarte de estas; 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.nextTick para este objective es mucho mejor ya que cuando use setTimeout , el cálculo y las verificaciones del tiempo transcurrido serán necesarios mientras que process.nextTick es simplemente lo que realmente queremos: “Hola tarea, regrese al final de la cola , has usado tu parte! ”

(Actualización 2016: los trabajadores web van a io.js – un nodo Node.js Node.js v7 – ver abajo).

(Actualización 2017: los trabajadores de la Web no van a Node.js v7 o v8 – ver más abajo.)

(Actualización 2018: los trabajadores web van al Node v10.5.0 de Node.js – ver abajo).

Alguna aclaración

Después de leer las respuestas anteriores, me gustaría señalar que no hay nada en los trabajadores de la web que esté en contra de la filosofía de JavaScript en general y de Nodo 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. Ningún estado es compartido. No hay problemas de locking. No hay locking No hay sincronización necesaria. Al igual que cuando usas un servicio RESTful desde tu progtwig Node, no te preocupa que ahora sea “multiproceso” porque el servicio RESTful no está en el mismo hilo que tu propio ciclo de eventos. Es solo un servicio separado al que accede asincrónicamente y eso es lo que importa.

Lo mismo es con los trabajadores de la web. Es solo una API para comunicarse con código que se ejecuta en un contexto completamente separado y si está en un hilo diferente, proceso diferente, diferente cgroup, zona, contenedor o máquina diferente es completamente irrelevante, debido a una API estrictamente asíncrona y no bloqueante. con todos los datos pasados ​​por valor

De hecho, los trabajadores de la web son, conceptualmente, un ajuste perfecto para Node que, como mucha gente desconoce, usa hilos de manera muy intensa y, de hecho, “todo funciona en paralelo, excepto tu código”.

  • Comprender el ciclo de eventos node.js de Mikito Takada
  • Entendiendo node.js por Felix Geisendörfer
  • Comprender el Node.js Event Loop de Trevor Norris
  • Node.js en sí mismo está bloqueando, solo su E / S no bloquea por Jeremy Epstein

Pero los trabajadores de la web ni siquiera necesitan implementarse usando hilos. Puede utilizar procesos, hilos verdes o incluso servicios RESTful en la nube, siempre que se utilice la API del trabajador web. La belleza de la API de paso de mensajes con semántica llamada por valor es que la implementación subyacente es prácticamente irrelevante, ya que los detalles del modelo de simultaneidad no quedarán expuestos.

Un bucle de evento de subproceso único es perfecto para operaciones vinculadas a E / S. No funciona tan bien para las operaciones vinculadas a la CPU, especialmente las de larga ejecución. Para eso necesitamos generar más procesos o usar hilos. 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 tarea excesiva para tareas simples, mientras que el uso de hilos significa lidiar con lockings y problemas de sincronización que son muy difíciles de hacer bien.

Lo que a menudo se recomienda es dividir las operaciones de larga duración vinculadas a la CPU 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 casi todo en JavaScript).

Módulos de nodo

Hay pocos módulos que se supone que deben agregar Web Workers a Node:

No he usado ninguno de ellos, pero tengo dos observaciones rápidas que pueden ser relevantes: a partir de 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 del uso de node-webworker-threads que puede usar una función en lugar de un nombre de archivo como argumento para el constructor Worker, lo que parece que puede ocasionar problemas sutiles si se implementa utilizando hilos que comparten memoria (a menos que funciones se usa solo para su método .toString () y se comstack de otra forma en un entorno diferente, en cuyo caso puede estar bien; tengo que analizarlo más profundamente, solo compartir mis observaciones aquí).

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

Actualización 1

Todavía no lo sabía al momento de escribir, pero un día antes de escribir esta respuesta, Web Workers se agregó a io.js.

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

No solo demuestra el hecho de 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, pero puede resultar en que los trabajadores de la web sean ciudadanos de primer nivel en JavaScript del lado del servidor como io. js (y posiblemente Node.js en el futuro) del mismo modo que ya lo está en JavaScript del lado del cliente en todos los navegadores modernos .

Actualización 2

En la Actualización 1 y mi tweet me refería a la solicitud de extracción 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 en virtud de 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: Están los trabajadores: compromiso inicial de implementación realizado por Petka Antonov desde el 6 de septiembre de 2015 que se puede descargar y probar en este árbol . Vea los comentarios de NiCk Newman para más detalles.

Actualización 4

A partir de 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 me preguntó por el estado actual de esta característica en los comentarios de relaciones públicas.

Las primeras respuestas en la discusión de RP fueron escépticas, pero más tarde Ben Noordhuis escribió que “Conseguir que esto se fusione de una forma u otra está en mi lista de tareas para v7”.

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

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

Actualización 5

A partir de julio de 2016, hay pocos módulos en npm que no estaban disponibles antes: para obtener una lista completa de módulos relevantes, buscar npm para trabajadores, trabajadores web, etc. Si algo en particular le resulta o no, envíe un comentario.

Actualización 6

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

La solicitud de extracción # 2133 trabajadores: la implementación inicial de Petka Antonov del 8 de julio de 2015 fue finalmente cerrada por Ben Noordhuis el 11 de diciembre de 2016, quien comentó que “el soporte multihilo agrega demasiados modos de falla nuevos para un beneficio insuficiente” y ” también puede lograr eso usando medios más tradicionales como memoria compartida y serialización más eficiente “.

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

Gracias de nuevo 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 de la web aparecieron en el nodo v10.5.0 como una función experimental activada con la bandera --experimental-worker .

Para más información, ver:

  • Publicación de blog de la publicación Node v10.5.0
  • Pull Request # 20876 – worker: implementación inicial por Anna Henningsen
  • Mi tweet original de felicidad cuando supe que esto entró en la versión 10.5.0:

🎉🎉🎉 ¡Finalmente! Puedo hacer la 7ma actualización de mi respuesta Stack Overflow de 3 años donde argumento que enhebrar a los trabajadores de la web no va en contra de la filosofía de Node, ¡solo que esta vez diciendo que finalmente lo conseguimos! 😜👍

Vengo de la vieja escuela de pensamiento donde utilizamos 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 esto. Como hasanyasin explicó en detalle cómo funciona el nodo y el concepto de funcionalidad asíncrona. Pero déjame agregar algunas cosas aquí.

En los viejos tiempos con núcleos individuales y velocidades de reloj más bajas, probamos varias formas de hacer que el software funcionara rápido y en paralelo. en días de DOS, utilizamos para ejecutar un progtwig a la vez. Que en Windows comenzamos a ejecutar múltiples aplicaciones (procesos) juntas. Conceptos como preventivo y no preventivo (o cooperativo) donde se probaron. ahora sabemos que la prevención fue la respuesta para una mejor tarea de procesamiento múltiple en computadoras de núcleo único. A lo largo vinieron 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 del proceso. El hilo fue acuñado como una alternativa ligera a los nuevos procesos de desove.

Así que, le guste o no la señal de la cadena o no multi-core o single core, sus procesos serán reemplazados por el sistema operativo.

Nodejs es un proceso único y proporciona un mecanismo asincrónico. Aquí los trabajos se envían al sistema operativo subyacente para realizar tareas mientras esperamos en un bucle de eventos para que la tarea finalice. Una vez que recibimos una señal verde del sistema operativo, hacemos lo que necesitamos hacer. Ahora, en cierto modo, se trata de multitareas cooperativas / no preventivas, por lo que nunca deberíamos bloquear el ciclo de eventos durante un largo período de tiempo, de lo contrario degradaremos nuestra aplicación muy rápido.
Entonces, si alguna vez hay una tarea que bloquea en la naturaleza o consume mucho tiempo, tendremos que ramificarla al mundo preventivo del sistema operativo y los hilos. hay buenos ejemplos de esto en la documentación de libuv . Además, si lee más la documentación, encontrará que FileI / O se maneja en hilos en node.js.

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

Under hood en node.js es todo c ++ y threads. Y el nodo proporciona una forma C ++ para extender su funcionalidad y acelerar aún más mediante el uso de subprocesos donde son obligatorios, es decir, tareas de locking, como leer desde una fuente de escritura a una fuente, análisis de datos de gran tamaño, etcétera.

Sé que la respuesta es la aceptada, pero para mí los hilos existirán sin importar lo que diga o cómo los oculte detrás de las secuencias de comandos, en segundo lugar, nadie solo divide las secuencias en cadenas solo por la velocidad, principalmente para tareas de locking. Y los hilos están en la parte posterior de Node.js, por lo que antes de atacar completamente los subprocesos múltiples es correcto. Además, los hilos son diferentes de los procesos y la limitación de tener procesos de nodos por núcleo no se aplica exactamente al número de hilos, los hilos son como subtareas de un proceso. de hecho, los hilos ganados; t aparecen en el administrador de tareas de Windows o en el comando superior de Linux. una vez más, tienen menos peso que procesos

No estoy seguro 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 yo entiendo, también son bloqueantes, es decir, son multitareas voluntarias, por lo que puede usarlas, pero debe gestionar los cambios de contexto usted mismo a través del yield . Los hilos pueden ser realmente lo que necesitas, pero no sé qué tan maduros están en node.js.

worker_threads ha sido implementado y enviado detrás de una bandera en node@10.5.0 . Todavía es una implementación inicial y se necesitan más esfuerzos para hacerlo más eficiente en lanzamientos futuros. Vale la pena intentarlo en el último node .

En las opiniones de muchos desarrolladores de nodo, una de las mejores partes de Node es en realidad su naturaleza de subproceso único. Los subprocesos introducen toda una serie de dificultades con recursos compartidos que Nodo evita por completo al no hacer nada más que IO sin locking.

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

Para tratar con la progtwigción asincrónica en su código (como en, evitando las pirámides de callback anidadas), el componente [Futuro] en la biblioteca de Fibras es una opción decente. También te sugiero que revises Asyncblock, que está basado en Fibras. Las fibras son agradables porque le permiten ocultar la callback duplicando la stack y luego saltando entre stacks en un solo hilo a medida que se necesitan. Le ahorra la molestia de los hilos reales mientras le da los beneficios. La desventaja es que los rastros de stack pueden ponerse un poco raros cuando se usan fibras, pero no son tan malos.

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

Tal vez un poco más de información sobre las tareas que está realizando ayude. ¿Por qué necesitarías (como mencionaste en tu 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 fork u otro método) que siempre se ejecuta y puede comunicarse a través del uso de 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á ejecutándose y obtenga una respuesta cuando finalice. Honestamente, no veo que poner en marcha muchos miles de subprocesos reales sea muy eficiente tampoco, 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 puede lograr lo que necesita.