Quel serait le meilleur pour les tâches simultanées sur node.js? Des fibres? Web-workers? ou Threads?

111

Je suis tombé sur node.js il y a quelque temps et je l'aime beaucoup. Mais j'ai vite découvert qu'il lui manquait cruellement la capacité d'effectuer des tâches gourmandes en ressources processeur. J'ai donc commencé à chercher sur Google et j'ai obtenu ces réponses pour résoudre le problème: Fibres, Webworkers et Threads (thread-a-gogo). Maintenant, lequel utiliser est une confusion et l'un d'eux doit absolument être utilisé - après tout, quel est le but d'avoir un serveur qui est juste bon en IO et rien d'autre? Suggestions nécessaires!

METTRE À JOUR:

Je pensais à un moyen tardif; juste besoin de suggestions dessus. Maintenant, ce à quoi j'ai pensé était ceci: Ayons quelques threads (en utilisant thread_a_gogo ou peut-être des webworkers). Désormais, lorsque nous en avons besoin de plus, nous pouvons en créer davantage. Mais il y aura une certaine limite sur le processus de création. (non impliqué par le système mais probablement à cause de la surcharge). Maintenant, lorsque nous dépassons la limite, nous pouvons créer un nouveau nœud et commencer à créer des threads dessus. De cette façon, cela peut continuer jusqu'à ce que nous atteignions une certaine limite (après tout, les processus ont aussi une grosse surcharge). Lorsque cette limite est atteinte, nous commençons à mettre les tâches en file d'attente. Chaque fois qu'un thread devient libre, une nouvelle tâche lui est assignée. De cette façon, cela peut se dérouler en douceur.

Alors, c'est ce à quoi j'ai pensé. Cette idée est-elle bonne? Je suis un peu nouveau dans tout ce processus et ces sujets, donc je n'ai aucune expertise en la matière. Veuillez partager vos opinions.

Merci. :)

Parth Thakkar
la source
Remarque: les ouvriers sont une spécification de navigateur et non une fonctionnalité Javascript.
FredTheWebGuy
Eh bien, je vois ça. Ma question concernait node.js - code serveur et non côté client!
Parth Thakkar
Juste une clarification - je vois que la question originale portait sur les Webworkers dans NodeJs, ce qui est impossible - NodeJs utilise "Threads". Cependant, il existe un module NodeJS flottant qui permet la syntaxe WebWorker dans le runtime NodeJs.
FredTheWebGuy

Réponses:

331

Node a un paradigme complètement différent et une fois qu'il est correctement capturé, il est plus facile de voir cette manière différente de résoudre les problèmes. Vous n'avez jamais besoin de plusieurs threads dans une application Node (1) car vous avez une manière différente de faire la même chose. Vous créez plusieurs processus; mais c'est très très différent, par exemple, de la façon dont Prefork mpm d'Apache Web Server le fait.

Pour l'instant, pensons que nous n'avons qu'un seul cœur de processeur et nous allons développer une application (à la manière de Node) pour faire un peu de travail. Notre travail consiste à traiter un gros fichier en cours d'exécution sur son contenu octet par octet. La meilleure façon pour notre logiciel est de commencer le travail depuis le début du fichier, de le suivre octet par octet jusqu'à la fin.

- Hé, Hasan, je suppose que tu es soit un débutant, soit une très vieille école du temps de mon grand-père !!! Pourquoi ne pas créer des threads et le rendre beaucoup plus rapide?

- Oh, nous n'avons qu'un seul cœur de processeur.

-- Et alors? Créez des fils, faites-le plus vite!

-- Ça ne marche pas comme ça. Si je crée des fils, je vais le ralentir. Parce que j'ajouterai beaucoup de frais généraux au système pour basculer entre les threads, en essayant de leur donner un peu de temps, et à l'intérieur de mon processus, en essayant de communiquer entre ces threads. En plus de tous ces faits, je devrai également réfléchir à la façon dont je vais diviser un même travail en plusieurs morceaux qui peuvent être réalisés en parallèle.

- D'accord, je vois que tu es pauvre. Utilisons mon ordinateur, il a 32 cœurs!

- Wow, tu es génial mon cher ami, merci beaucoup. Je vous en suis reconnaissant!

Ensuite, nous retournons au travail. Nous avons maintenant 32 cœurs cpu grâce à notre riche ami. Les règles que nous devons respecter viennent de changer. Maintenant, nous voulons utiliser toute cette richesse qui nous est donnée.

Pour utiliser plusieurs cœurs, nous devons trouver un moyen de diviser notre travail en morceaux que nous pouvons gérer en parallèle. Si ce n'était pas Node, nous utiliserions des threads pour cela; 32 threads, un pour chaque cœur de processeur. Cependant, puisque nous avons Node, nous allons créer 32 processus Node.

Les threads peuvent être une bonne alternative aux processus Node, peut-être même un meilleur moyen; mais seulement dans un type de travail spécifique où le travail est déjà défini et nous avons un contrôle total sur la façon de le gérer. En dehors de cela, pour tout autre type de problème où le travail vient de l'extérieur d'une manière que nous n'avons pas de contrôle et que nous voulons répondre le plus rapidement possible, la manière de Node est incontestablement supérieure.

- Hé, Hasan, tu travailles toujours avec un seul thread? Qu'est-ce qui ne va pas avec toi, mec? Je viens de vous fournir ce que vous vouliez. Vous n'avez plus d'excuses. Créez des threads, accélérez-le.

- J'ai divisé le travail en morceaux et chaque processus fonctionnera sur l'une de ces pièces en parallèle.

- Pourquoi ne créez-vous pas de fils?

- Désolé, je ne pense pas que ce soit utilisable. Vous pouvez emporter votre ordinateur si vous le souhaitez?

- Non d'accord, je suis cool, je ne comprends juste pas pourquoi vous n'utilisez pas de fils?

- Merci pour l'ordinateur. :) J'ai déjà divisé le travail en morceaux et je crée des processus pour travailler sur ces morceaux en parallèle. Tous les cœurs du processeur seront pleinement utilisés. Je pourrais le faire avec des threads au lieu de processus; mais Node a cette façon et mon patron Parth Thakkar veut que j'utilise Node.

- D'accord, faites-moi savoir si vous avez besoin d'un autre ordinateur. : p

Si je crée 33 processus, au lieu de 32, le planificateur du système d'exploitation mettra en pause un thread, démarrera l'autre, le mettra en pause après quelques cycles, redémarrera l'autre ... C'est une surcharge inutile. Je ne le veux pas. En fait, sur un système avec 32 cœurs, je ne voudrais même pas créer exactement 32 processus, 31 peuvent être plus agréables . Parce que ce n'est pas seulement mon application qui fonctionnera sur ce système. Laisser un peu de place pour d'autres choses peut être bien, surtout si nous avons 32 chambres.

Je pense que nous sommes sur la même longueur d'onde maintenant sur l'utilisation complète des processeurs pour les tâches gourmandes en CPU .

- Hmm, Hasan, je suis désolé de me moquer un peu de toi. Je crois que je te comprends mieux maintenant. Mais il y a encore quelque chose dont j'ai besoin d'une explication: qu'est-ce que tout le buzz autour de l'exécution de centaines de threads? Je lis partout que les threads sont beaucoup plus rapides à créer et stupides que les processus de fourche? Vous forkez des processus au lieu de threads et vous pensez que c'est le plus élevé que vous obtiendriez avec Node. Alors Node n'est-il pas approprié pour ce genre de travail?

- Pas de soucis, je suis cool aussi. Tout le monde dit ces choses, alors je pense que j'ai l'habitude de les entendre.

-- Alors? Node n'est pas bon pour ça?

- Node est parfaitement adapté à cela même si les threads peuvent l'être aussi. Quant à la surcharge de création de thread / processus; sur des choses que vous répétez beaucoup, chaque milliseconde compte. Cependant, je ne crée que 32 processus et cela prendra très peu de temps. Cela n'arrivera qu'une seule fois. Cela ne fera aucune différence.

- Quand est-ce que je veux créer des milliers de fils, alors?

- Vous ne voulez jamais créer des milliers de fils. Cependant, sur un système qui effectue un travail qui vient de l'extérieur, comme un serveur Web traitant des requêtes HTTP; si vous utilisez un thread pour chaque requête, vous allez créer beaucoup de threads, dont beaucoup.

- Node est différent, cependant? Droite?

-- Oui, exactement. C'est là que Node brille vraiment. Tout comme un thread est beaucoup plus léger qu'un processus, un appel de fonction est beaucoup plus léger qu'un thread. Le nœud appelle des fonctions au lieu de créer des threads. Dans l'exemple d'un serveur Web, chaque requête entrante provoque un appel de fonction.

-- Hum ... intéressant; mais vous ne pouvez exécuter qu'une seule fonction à la fois si vous n'utilisez pas plusieurs threads. Comment cela peut-il fonctionner lorsque de nombreuses requêtes arrivent sur le serveur Web en même temps?

- Vous avez parfaitement raison sur la manière dont les fonctions fonctionnent, une à la fois, jamais deux en parallèle. Je veux dire dans un seul processus, une seule portée de code est en cours d'exécution à la fois. L'OS Scheduler ne vient pas mettre en pause cette fonction et passer à une autre, à moins qu'il n'interrompe le processus pour donner du temps à un autre processus, pas à un autre thread de notre processus. (2)

- Alors, comment un processus peut-il gérer 2 demandes à la fois?

- Un processus peut traiter des dizaines de milliers de requêtes à la fois tant que notre système dispose de suffisamment de ressources (RAM, réseau, etc.). Le fonctionnement de ces fonctions est LA DIFFÉRENCE CLÉ.

- Hmm, devrais-je être excité maintenant?

- Peut-être :) Node exécute une boucle sur une file d'attente. Dans cette file d'attente se trouvent nos travaux, c'est-à-dire les appels que nous avons commencé à traiter les demandes entrantes. Le point le plus important ici est la façon dont nous concevons nos fonctions pour qu'elles s'exécutent. Au lieu de commencer à traiter une demande et de faire attendre l'appelant jusqu'à ce que nous ayons terminé le travail, nous terminons rapidement notre fonction après avoir effectué une quantité de travail acceptable. Lorsque nous arrivons à un point où nous devons attendre qu'un autre composant fasse du travail et nous renvoie une valeur, au lieu d'attendre cela, nous finissons simplement notre fonction en ajoutant le reste du travail à la file d'attente.

- Cela semble trop complexe?

- Non non, je peux paraître complexe; mais le système lui-même est très simple et il est parfaitement logique.

Maintenant, je veux arrêter de citer le dialogue entre ces deux développeurs et terminer ma réponse après un dernier exemple rapide du fonctionnement de ces fonctions.

De cette façon, nous faisons ce que ferait normalement OS Scheduler. Nous suspendons notre travail à un moment donné et laissons d'autres appels de fonction (comme d'autres threads dans un environnement multi-thread) s'exécuter jusqu'à ce que nous ayons à nouveau notre tour. C'est bien mieux que de laisser le travail à OS Scheduler qui essaie de donner juste du temps à chaque thread sur le système. Nous savons ce que nous faisons beaucoup mieux que OS Scheduler et nous devons nous arrêter quand nous devrions arrêter.

Voici un exemple simple où nous ouvrons un fichier et le lisons pour travailler sur les données.

Voie synchrone:

Open File
Repeat This:    
    Read Some
    Do the work

Manière asynchrone:

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

Comme vous le voyez, notre fonction demande au système d'ouvrir un fichier et n'attend pas son ouverture. Il se termine en fournissant les étapes suivantes une fois le fichier prêt. À notre retour, Node exécute d'autres appels de fonction sur la file d'attente. Après avoir parcouru toutes les fonctions, la boucle d'événements passe au tour suivant ...

En résumé, Node a un paradigme complètement différent du développement multi-thread; mais cela ne veut pas dire qu'il manque de choses. Pour un travail synchrone (où nous pouvons décider de l'ordre et du mode de traitement), cela fonctionne aussi bien que le parallélisme multi-thread. Pour un travail qui vient de l'extérieur comme des requêtes à un serveur, c'est tout simplement supérieur.


(1) À moins que vous ne construisiez des bibliothèques dans d'autres langages comme C / C ++, auquel cas vous ne créez toujours pas de threads pour diviser les tâches. Pour ce genre de travail, vous avez deux threads dont l'un continuera à communiquer avec Node tandis que l'autre fera le vrai travail.

(2) En fait, chaque processus Node a plusieurs threads pour les mêmes raisons que j'ai mentionnées dans la première note de bas de page. Cependant, ce n'est pas comme 1000 threads effectuant des travaux similaires. Ces threads supplémentaires servent à accepter des événements d'E / S et à gérer la messagerie inter-processus.

UPDATE (comme réponse à une bonne question dans les commentaires)

@Mark, merci pour la critique constructive. Dans le paradigme de Node, vous ne devriez jamais avoir de fonctions qui prennent trop de temps à traiter à moins que tous les autres appels de la file d'attente ne soient conçus pour être exécutés les uns après les autres. Dans le cas de tâches coûteuses en calcul, si nous regardons l'image dans son intégralité, nous voyons que ce n'est pas une question de "Devrions-nous utiliser des threads ou des processus?" mais une question de "Comment pouvons-nous diviser ces tâches d'une manière bien équilibrée en sous-tâches que nous pouvons les exécuter en parallèle en utilisant plusieurs cœurs de processeur sur le système?" Disons que nous traiterons 400 fichiers vidéo sur un système à 8 cœurs. Si nous voulons traiter un fichier à la fois, nous avons besoin d'un système qui traitera différentes parties du même fichier, auquel cas, peut-être, un système à processus unique multi-thread sera plus facile à construire et encore plus efficace. Nous pouvons toujours utiliser Node pour cela en exécutant plusieurs processus et en passant des messages entre eux lorsque le partage d'état / la communication est nécessaire. Comme je l'ai déjà dit, une approche multi-processus avec Node estainsi qu'une approche multithread dans ce genre de tâches; mais pas plus que ça. Encore une fois, comme je l'ai déjà dit, la situation dans laquelle Node brille est lorsque nous avons ces tâches en tant qu'entrée dans le système à partir de plusieurs sources, car conserver de nombreuses connexions simultanément est beaucoup plus léger dans Node par rapport à un thread par connexion ou un processus par connexion. système.

Quant aux setTimeout(...,0)appels; Parfois, donner une pause pendant une tâche longue pour permettre aux appels dans la file d'attente d'avoir leur part de traitement peut être nécessaire. La division des tâches de différentes manières peut vous en éviter; mais encore, ce n'est pas vraiment un hack, c'est juste la façon dont les files d'attente d'événements fonctionnent. Aussi, utiliser process.nextTickpour cet objectif est bien meilleur puisque lorsque vous utilisez setTimeout, le calcul et les vérifications du temps passé seront nécessaires alors que process.nextTickc'est simplement ce que nous voulons vraiment: "Hé tâche, retournez à la fin de la file d'attente, vous avez utilisé votre part! "

hasanyasin
la source
9
Incroyable! Putain incroyable! J'ai adoré la façon dont vous avez répondu à cette question! :)
Parth Thakkar
48
Bien sûr :) Je ne peux vraiment pas croire qu'il y ait des gens extrêmement méchants qui votent pour cet article-réponse! L'interlocuteur l'appelle "Damn Amazing!" et un auteur de livre me propose d'écrire sur son site Web après avoir vu cela; mais certains génies y votent contre. Pourquoi ne partagez-vous pas votre brillante qualité intellectuelle et ne commentez-vous pas dessus au lieu de voter méchamment et sournoisement vers le bas, hein? Pourquoi quelque chose de gentil vous dérange autant? Pourquoi voulez-vous empêcher quelque chose d'utile d'atteindre d'autres personnes qui peuvent vraiment en bénéficier?
hasanyasin
9
Ce n'est pas une réponse tout à fait juste. Qu'en est-il des tâches coûteuses en calcul, où nous ne pouvons pas «terminer rapidement» notre appel de fonction? Je pense que certaines personnes utilisent des setTimeout(...,0)hacks pour cela, mais utiliser un fil séparé dans ce scénario serait sûrement mieux?
mpen
3
@hasanyasin C'est la plus belle explication sur le nœud que j'ai trouvée jusqu'à présent! :)
Venemo
7
@Mark En général, si le calcul est si coûteux, il existe des options / modules pour les travailleurs de la bande de roulement / processus ... En général, pour ce type de choses, j'utilise un Message Queue, et j'ai des processus de travail qui gèrent une tâche à un heure de la file d'attente et exécutez cette tâche. Cela permet également de passer à plusieurs serveurs. Dans ce sens, Substack propose de nombreux modules orientés vers l'approvisionnement et la mise à l'échelle que vous pouvez consulter.
Tracker1
34

(Mise à jour 2016: les web workers vont dans io.js - un fork de Node.js Node.js v7 - voir ci-dessous.)

(Mise à jour 2017: les travailleurs Web n'entrent pas dans Node.js v7 ou v8 - voir ci-dessous.)

(Mise à jour 2018: les travailleurs Web entrent dans Node.js Node v10.5.0 - voir ci-dessous.)

Quelques clarifications

Après avoir lu les réponses ci-dessus, je voudrais souligner qu'il n'y a rien chez les web workers qui soit contre la philosophie de JavaScript en général et de Node en particulier en ce qui concerne la concurrence. (S'il y en avait, cela ne serait même pas discuté par le WHATWG, encore moins implémenté dans les navigateurs).

Vous pouvez considérer un travailleur Web comme un microservice léger auquel on accède de manière asynchrone. Aucun état n'est partagé. Aucun problème de verrouillage n'existe. Il n'y a pas de blocage. Aucune synchronisation n'est nécessaire. Tout comme lorsque vous utilisez un service RESTful à partir de votre programme Node, vous ne vous inquiétez pas qu'il soit maintenant "multithread" car le service RESTful n'est pas dans le même thread que votre propre boucle d'événements. C'est juste un service séparé auquel vous accédez de manière asynchrone et c'est ce qui compte.

Il en va de même pour les web workers. C'est juste une API pour communiquer avec du code qui s'exécute dans un contexte complètement séparé et que ce soit dans un thread différent, un processus différent, un groupe de contrôle différent, une zone, un conteneur ou une machine différente est complètement hors de propos, en raison d'une API strictement asynchrone et non bloquante, avec toutes les données passées par valeur.

En fait, les web workers sont conceptuellement un ajustement parfait pour Node qui - comme beaucoup de gens ne le savent pas - utilise d'ailleurs assez fortement les threads, et en fait "tout fonctionne en parallèle sauf votre code" - voir:

Mais les web workers n'ont même pas besoin d'être implémentés à l'aide de threads. Vous pouvez utiliser des processus, des threads verts ou même des services RESTful dans le cloud, à condition que l'API de travail Web soit utilisée. Toute la beauté de l'API de transmission de messages avec une sémantique appel par valeur est que l'implémentation sous-jacente est quasiment hors de propos, car les détails du modèle de concurrence ne seront pas exposés.

Une boucle d'événements à thread unique est parfaite pour les opérations liées aux E / S. Cela ne fonctionne pas très bien pour les opérations liées au processeur, en particulier celles de longue durée. Pour cela, nous devons générer plus de processus ou utiliser des threads. La gestion des processus enfants et de la communication inter-processus de manière portable peut être assez difficile et elle est souvent considérée comme une surpuissance pour des tâches simples, tandis que l'utilisation de threads signifie gérer les verrous et les problèmes de synchronisation qui sont très difficiles à faire correctement.

Ce qui est souvent recommandé est de diviser les opérations de longue durée liées au processeur en tâches plus petites (quelque chose comme l'exemple dans la section "Réponse originale" de ma réponse à Accélérer setInterval ) mais ce n'est pas toujours pratique et cela n'utilise pas plus plus d'un cœur de processeur.

Je l'écris pour clarifier les commentaires qui disaient essentiellement que les web workers ont été créés pour les navigateurs, pas pour les serveurs (en oubliant qu'on peut dire à peu près tout en JavaScript).

Modules de nœud

Il existe quelques modules censés ajouter des Web Workers à Node:

Je n'en ai utilisé aucun mais j'ai deux observations rapides qui peuvent être pertinentes: en mars 2015, node-webworker a été mis à jour pour la dernière fois il y a 4 ans et node-webworker-threads a été mis à jour pour la dernière fois il y a un mois. Je vois également dans l'exemple d'utilisation de node-webworker-threads que vous pouvez utiliser une fonction au lieu d'un nom de fichier comme argument pour le constructeur Worker, ce qui semble pouvoir causer des problèmes subtils s'il est implémenté à l'aide de threads qui partagent la mémoire (à moins que le fonctions n'est utilisée que pour sa méthode .toString () et est par ailleurs compilée dans un environnement différent, auquel cas cela peut convenir - je dois l'examiner plus en profondeur, en partageant simplement mes observations ici).

S'il existe un autre projet pertinent qui implémente l'API des travailleurs Web dans Node, veuillez laisser un commentaire.

Mise à jour 1

Je ne savais pas encore au moment de l' écriture , mais d' ailleurs un jour avant que j'ai écrit cette réponse Web Workers ont été ajoutés à io.js .

( io.js est un fork de Node.js - voir: Pourquoi io.js a décidé de fork Node.js , une interview d'InfoWorld avec Mikeal Rogers, pour plus d'informations.)

Non seulement cela prouve qu'il n'y a rien chez les travailleurs Web qui soit contre la philosophie de JavaScript en général et de Node en particulier en ce qui concerne la concurrence, mais cela peut faire des travailleurs Web un citoyen de première classe dans JavaScript côté serveur comme io. js (et éventuellement Node.js dans le futur) tout comme il est déjà en JavaScript côté client dans tous les navigateurs modernes .

Mise à jour 2

Dans la mise à jour 1 et mon tweet, je faisais référence à la demande d'extraction io.js # 1159 qui redirige maintenant vers le nœud PR # 1159 qui a été fermé le 8 juillet et remplacé par le nœud PR # 2133 - qui est toujours ouvert. Il y a des discussions en cours sous ces pull requests qui peuvent fournir des informations plus à jour sur le statut des agents Web dans io.js / Node.js.

Mise à jour 3

Dernières infos - merci à NiCk Newman pour l'avoir postée dans les commentaires: Voici les ouvriers: commit d' implémentation initial par Petka Antonov du 6 septembre 2015 qui peut être téléchargé et essayé dans cet arbre . Voir les commentaires de NiCk Newman pour plus de détails.

Mise à jour 4

En mai 2016, les derniers commentaires sur le PR # 2133 encore ouvert - travailleurs: la mise en œuvre initiale datait de 3 mois. Le 30 mai, Matheus Moreira m'a demandé de publier une mise à jour de cette réponse dans les commentaires ci-dessous et il a demandé l'état actuel de cette fonctionnalité dans les commentaires des relations publiques.

Les premières réponses dans la discussion PR étaient sceptiques mais plus tard Ben Noordhuis a écrit que "Obtenir ceci fusionné dans une forme ou une autre est sur ma liste de choses à faire pour la v7".

Tous les autres commentaires semblaient confirmer cela et à partir de juillet 2016, il semble que Web Workers devrait être disponible dans la prochaine version de Node , la version 7.0 qui devrait être publiée en octobre 2016 (pas nécessairement sous la forme de ce PR exact).

Merci à Matheus Moreira pour l'avoir signalé dans les commentaires et relancé la discussion sur GitHub.

Mise à jour 5

En juillet 2016, il y a quelques modules sur npm qui n'étaient pas disponibles auparavant - pour une liste complète des modules pertinents, recherchez npm pour les travailleurs, les travailleurs Web, etc. Si quelque chose en particulier fonctionne ou ne fonctionne pas pour vous, veuillez publier un commentaire.

Mise à jour 6

À partir de janvier 2017, il est peu probable que les travailleurs Web soient fusionnés dans Node.js.

La pull request # 2133 workers: la mise en œuvre initiale par Petka Antonov à partir du 8 juillet 2015 a finalement été clôturée par Ben Noordhuis le 11 décembre 2016 qui a commenté que "le support multi-threading ajoute trop de nouveaux modes d'échec pour pas assez d'avantages" et "nous peut également accomplir cela en utilisant des moyens plus traditionnels comme la mémoire partagée et une sérialisation plus efficace. "

Pour plus d'informations, consultez les commentaires du PR 2133 sur GitHub.

Merci encore à Matheus Moreira pour l'avoir signalé dans les commentaires.

Mise à jour 6

Je suis heureux d'annoncer qu'il y a quelques jours, en juin 2018, les web workers sont apparus dans Node v10.5.0 en tant que fonctionnalité expérimentale activée avec le --experimental-workerdrapeau.

Pour plus d'informations, consultez:

🎉🎉🎉 Enfin! Je peux faire la 7ème mise à jour de ma réponse Stack Overflow de 3 ans où je soutiens que le threading à la web workers n'est pas contre la philosophie de Node, mais cette fois en disant que nous l'avons finalement obtenu! 😜👍

rsp
la source
1
@NiCkNewman Merci. Je vois que la demande d'extraction d'origine dans io.js est maintenant fermée et remplacée par une autre - avec quelques discussions dans les commentaires des demandes d'extraction sur GitHub, vous pourrez peut-être y trouver des informations. Voir: mise à jour 2 dans ma réponse.
rsp
1
Oui, il semble qu'ils viennent de résoudre le dernier problème de libuv. Je me demande quand je pourrai mettre la main sur le module. Ne peut pas attendre! Merci de nous avoir tenus au courant ~ Edit: Je viens de m'initialiser : github.com/petkaantonov/io.js/commit / ... On y va, ça s'en vient!
NiCk Newman
1
Oui, c'est en direct. (Pas encore officiellement implémenté) mais vous pouvez télécharger la source ici: github.com/petkaantonov/io.js/tree / ... et compiler si vous voulez le tester! Je le fais maintenant ~
NiCk Newman
1
@NiCkNewman Merci pour la nouvelle info - je l'ai ajoutée à la réponse.
rsp
1
Pouvez-vous nous mettre à jour sur l'état de la workersmise en œuvre de Node.js ? Les derniers commentaires dans le PR # 2133 datent de février; les développeurs ont apparemment rencontré un problème et aucun commentaire n'indique qu'il a été résolu.
Matheus Moreira
8

Je viens de la vieille école de pensée où nous utilisions le multi-threading pour rendre les logiciels rapides. Depuis 3 ans, j'utilise Node.js et un grand partisan de celui-ci. Comme hasanyasin a expliqué en détail comment fonctionne le nœud et le concept de fonctionnalité asyncrous. Mais permettez-moi d'ajouter quelques éléments ici.

À l'époque, avec des cœurs uniques et des vitesses d'horloge plus faibles, nous avons essayé différentes façons de faire fonctionner le logiciel rapidement et en parallèle. sous DOS, nous utilisons pour exécuter un programme à la fois. Que dans Windows, nous avons commencé à exécuter plusieurs applications (processus) ensemble. Des concepts comme préemptif et non préemptif (ou coopératif) ont été testés. nous savons maintenant que la prévention était la solution pour une meilleure tâche multi-traitement sur les ordinateurs monocœur. Viennent ensuite les concepts de processus / tâches et de changement de contexte. Que le concept de thread pour réduire davantage le fardeau du changement de contexte de processus. Thread a été inventé comme une alternative légère à la création de nouveaux processus.

Donc, que vous le vouliez ou non, le fil de signal ou non multi-core ou single core vos processus seront préemptés et temporisés par le système d'exploitation.

Nodejs est un processus unique et fournit un mécanisme asynchrone. Ici, les travaux sont envoyés au système d'exploitation sous-jacent pour effectuer des tâches pendant que nous attendons dans une boucle d'événements que la tâche se termine. Une fois que nous recevons un signal vert du système d'exploitation, nous exécutons ce que nous devons faire. Maintenant, d'une certaine manière, il s'agit d'un multitâche coopératif / non préemptif, nous ne devrions donc jamais bloquer la boucle d'événements pendant une très longue période de temps, sinon nous dégraderons notre application très rapidement.
Donc, s'il y a jamais une tâche qui est de nature bloquante ou qui prend beaucoup de temps, nous devrons la ramener au monde préemptif du système d'exploitation et des threads. il y a de bons exemples de ceci dans la documentation de libuv . Aussi , si vous lisez la documentation plus vous trouvez que FileI / O est traité dans les discussions en Node.js .

Donc, tout d'abord, tout est dans la conception de notre logiciel. Deuxièmement, le changement de contexte se produit toujours, peu importe ce qu'ils vous disent. Les threads sont là et toujours là pour une raison, la raison en est qu'ils sont plus rapides à basculer entre les processus.

Sous le capot dans node.js, tout est C ++ et threads. Et node fournit un moyen c ++ d'étendre ses fonctionnalités et d'accélérer davantage en utilisant des threads là où ils sont indispensables, c'est-à-dire en bloquant des tâches telles que la lecture d'une source en écriture vers une source, en analysant de grandes données, etc.

Je sais que la réponse hasanyasin est acceptée, mais pour moi, les threads existeront peu importe ce que vous dites ou la façon dont vous les cachez derrière des scripts, deuxièmement, personne ne se contente de casser les choses en threads juste pour la vitesse, c'est principalement fait pour bloquer les tâches. Et les threads sont dans la colonne vertébrale de Node.js, donc avant de dénigrer complètement le multi-threading, c'est correct. De plus, les threads sont différents des processus et la limitation d'avoir des processus de nœud par cœur ne s'applique pas exactement au nombre de threads, les threads sont comme des sous-tâches d'un processus. en fait, les threads ne s'affichent pas dans votre gestionnaire de tâches Windows ou dans la commande linux top. encore une fois, ils ont plus de poids que les processus

limplash
la source
Le code asynchrone n'est pas une énorme innovation (en fait, nous l'avons depuis des décennies) et le multithreading n'est pas une technologie obsolète à remplacer. Ce sont des outils différents avec des compromis différents, et en fait, ils peuvent même être assez bien combinés. Chaque fois que vous exécutez node-cluster, vous exécutez en fait plusieurs "threads" (processus dans ce cas, mais la même chose pourrait être obtenue avec des threads, et être encore plus léger). Ou prenez Erlang ou Go, qui peut exécuter des milliers de fils verts ...
Hejazzman
Je pense que le principal point qui nous manque, c'est que le processus sous le système d'exploitation sera toujours effectué de manière préventive pour assurer l'équité. De plus, avec plusieurs processeurs, vous pouvez avoir une exécution de code parallèle réelle, mais même dans ce cas, vous aurez la préemption. Le travail asynchrone est également effectué par le système d'exploitation dans certains for d'un processus.
limplash
4

Je ne suis pas sûr que les webworkers soient pertinents dans ce cas, ils sont des techniciens côté client (exécutés dans le navigateur), tandis que node.js s'exécute sur le serveur. Les fibres, pour autant que je sache, sont également bloquantes, c'est-à-dire qu'elles sont multitâches volontaires, vous pouvez donc les utiliser, mais vous devez gérer vous-même les changements de contexte via yield. Les threads sont peut-être ce dont vous avez besoin, mais je ne sais pas à quel point ils sont matures dans node.js.

Lanzz
la source
3
juste pour votre info, les webworkers ont été (partiellement) adaptés sur node.js. Et sont disponibles en node-workerspackage. Jetez un œil à ceci: github.com/cramforce/node-worker
Parth Thakkar
Bon à savoir, merci. Les documents sont très rares cependant, je n'ai aucune idée si cela fonctionne dans un thread, un processus séparé ou simplement dans le même processus, et je n'ai pas le temps de fouiller dans le code, donc je n'ai aucune idée si cela va travailler pour votre cas.
lanzz
@ParthThakkar: Ce projet n'a pas été touché depuis 3 ans (2 lorsque vous avez posté), et n'a pas dépassé 0.0.1.
mpen
@Mark: La raison de mon ignorance à ce sujet est que je ne suis pas encore un programmeur professionnel. Heck, je ne suis même pas dans une université. Je suis toujours un boursier du secondaire, qui continue à lire sur la programmation - en plus de gérer le travail scolaire. Donc, il n'est pas possible pour moi d'avoir des connaissances sur toutes ces questions. Je viens de
publier
@Mark: Même si c'était gentil de votre part de souligner cela à propos de l'histoire du projet. De telles choses seront prises en compte dans mes futures réponses !! :)
Parth Thakkar
3

worker_threadsa été implémenté et expédié derrière un drapeau en [email protected]. Il s'agit toujours d'une implémentation initiale et des efforts supplémentaires sont nécessaires pour le rendre plus efficace dans les versions futures. Cela vaut la peine de l'essayer en dernier node.

motss
la source
2

De l'avis de nombreux développeurs de Node, l'une des meilleures parties de Node est en fait sa nature à un seul thread. Les threads introduisent toute une série de difficultés avec les ressources partagées que Node évite complètement en ne faisant rien d'autre que des E / S non bloquantes.

Cela ne veut pas dire que Node est limité à un seul thread. C'est juste que la méthode pour obtenir la concurrence threadée est différente de ce que vous recherchez. La manière standard de traiter les threads consiste à utiliser le module de cluster fourni en standard avec Node lui-même. C'est une approche plus simple des threads que de les traiter manuellement dans votre code.

Pour gérer la programmation asynchrone dans votre code (comme dans, éviter les pyramides de rappel imbriquées), le composant [Future] de la bibliothèque Fibers est un choix décent. Je vous suggère également de consulter Asyncblock, basé sur Fibers. Les fibres sont bien car elles vous permettent de masquer le rappel en dupliquant la pile, puis en sautant entre les piles sur un seul thread au besoin. Vous évite les tracas des vrais threads tout en vous donnant les avantages. L'inconvénient est que les traces de pile peuvent devenir un peu bizarres lors de l'utilisation de Fibers, mais elles ne sont pas trop mauvaises.

Si vous n'avez pas besoin de vous soucier des trucs asynchrones et que vous êtes plus simplement intéressé à faire beaucoup de traitement sans blocage, un simple appel à process.nextTick (rappel) de temps en temps est tout ce dont vous avez besoin.

genericdave
la source
eh bien, votre suggestion - concernant les grappes - était ce à quoi j'avais initialement pensé. Mais le problème avec cela est leur surcharge - une nouvelle instance de v8 doit être initialisée à chaque fois qu'un nouveau processus est forké (~ 30 ms, 10 Mo). Donc, vous ne pouvez pas en créer beaucoup. Ceci est tiré directement de la documentation des nœuds: ces nœuds enfants (à propos des processus_enfants) sont encore de toutes nouvelles instances de la V8. Supposons au moins 30 ms de démarrage et 10 Mo de mémoire pour chaque nouveau nœud. Autrement dit, vous ne pouvez pas en créer plusieurs milliers.
Parth Thakkar
1
C'est exactement l'idée de cluster. Vous exécutez un worker par cœur de processeur. Tout autre élément est probablement inutile. Même les tâches intensives en CPU fonctionneront bien avec un style asynchrone. Cependant, si vous avez vraiment besoin de threads complets, vous devriez probablement envisager de passer entièrement à un autre serveur principal.
genericdave
1

Peut-être que des informations supplémentaires sur les tâches que vous effectuez pourraient vous aider. Pourquoi auriez-vous besoin (comme vous l'avez mentionné dans votre commentaire à la réponse de genericdave) d'en créer plusieurs milliers? La manière habituelle de faire ce genre de chose dans Node est de démarrer un processus de travail (en utilisant fork ou une autre méthode) qui s'exécute toujours et peut être communiqué à l'aide de messages. En d'autres termes, ne démarrez pas un nouveau collaborateur chaque fois que vous devez effectuer la tâche que vous effectuez, mais envoyez simplement un message au collaborateur déjà en cours d'exécution et obtenez une réponse une fois l'opération terminée. Honnêtement, je ne vois pas non plus que démarrer plusieurs milliers de threads réels serait très efficace, vous êtes toujours limité par vos processeurs.

Maintenant, après avoir dit tout cela, j'ai fait beaucoup de travail avec Hook.io ces derniers temps, ce qui semble très bien fonctionner pour ce genre de tâches de déchargement dans d'autres processus, peut-être qu'il peut accomplir ce dont vous avez besoin.

kbjr
la source