Je crains que je «fasse la mauvaise chose» ici, si c'est le cas, supprimez-moi et je m'excuse. En particulier, je ne vois pas comment je crée les petites annotations soignées que certains ont créées. Cependant, j'ai beaucoup de préoccupations / observations à faire sur ce fil.
1) L'élément commenté dans le pseudo-code dans l'une des réponses populaires
result = query( "select smurfs from some_mushroom" );
// twiddle fingers
go_do_something_with_result( result );
est essentiellement faux. Si le thread est informatique, alors ce n'est pas un coup de pouce, il fait le travail nécessaire. Si, d'un autre côté, il attend simplement la fin des E / S, alors il n'utilise pas le temps CPU, tout l'intérêt de l'infrastructure de contrôle des threads dans le noyau est que le CPU trouvera quelque chose d'utile à faire. La seule façon de "tourner les pouces" comme suggéré ici serait de créer une boucle d'interrogation, et personne qui a codé un vrai serveur Web n'est suffisamment incompétent pour le faire.
2) "Les threads sont durs", n'a de sens que dans le contexte du partage de données. Si vous avez des threads essentiellement indépendants, comme c'est le cas lors de la gestion des requêtes Web indépendantes, alors le threading est trivialement simple, il vous suffit de coder le flux linéaire de la façon de gérer un travail et de rester assis sachant qu'il gérera plusieurs demandes, et chacun sera effectivement indépendant. Personnellement, je me risquerais à dire que pour la plupart des programmeurs, l'apprentissage du mécanisme de fermeture / rappel est plus complexe que le simple codage de la version de thread de haut en bas. (Mais oui, si vous devez communiquer entre les threads, la vie devient très dure très vite, mais je ne suis pas convaincu que le mécanisme de fermeture / rappel change vraiment cela, il restreint simplement vos options, car cette approche est toujours réalisable avec les threads Quoi qu'il en soit,
3) Jusqu'à présent, personne n'a présenté de preuve réelle pour expliquer pourquoi un type particulier de changement de contexte prendrait plus ou moins de temps que tout autre type. Mon expérience dans la création de noyaux multitâches (à petite échelle pour les contrôleurs intégrés, rien de si sophistiqué qu'un "vrai" OS) suggère que ce ne serait pas le cas.
4) Toutes les illustrations que j'ai vues à ce jour qui prétendent montrer à quel point Node est plus rapide que les autres serveurs Web sont horriblement imparfaites, cependant, elles sont imparfaites d'une manière qui illustre indirectement un avantage que j'accepterais certainement pour Node (et c'est nullement insignifiant). Le nœud ne semble pas avoir besoin (ni même permis, en fait) de réglage. Si vous avez un modèle fileté, vous devez créer suffisamment de threads pour gérer la charge attendue. Faites-le mal et vous vous retrouverez avec de mauvaises performances. S'il y a trop peu de threads, alors le CPU est inactif, mais incapable d'accepter plus de requêtes, de créer trop de threads, et vous gaspillerez la mémoire du noyau, et dans le cas d'un environnement Java, vous gaspillerez également la mémoire de tas principale . Maintenant, pour Java, le gaspillage de tas est le premier, le meilleur, moyen de bousiller les performances du système, parce que la collecte efficace des ordures (actuellement, cela pourrait changer avec G1, mais il semble que le jury soit encore sur ce point au début de 2013 au moins) dépend du fait d'avoir beaucoup de tas de rechange. Donc, il y a le problème, ajustez-le avec trop peu de threads, vous avez des processeurs inactifs et un débit médiocre, ajustez-le avec trop de threads, et cela s'embourbe d'autres façons.
5) Il y a une autre manière d'accepter la logique de l'affirmation selon laquelle l'approche de Node "est plus rapide par conception", et c'est celle-ci. La plupart des modèles de threads utilisent un modèle de changement de contexte à tranches de temps, superposé au modèle préemptif plus approprié (alerte de jugement de valeur :) et plus efficace (pas de jugement de valeur). Cela se produit pour deux raisons, premièrement, la plupart des programmeurs ne semblent pas comprendre la préemption de priorité, et deuxièmement, si vous apprenez le filetage dans un environnement Windows, le découpage du temps est là, que cela vous plaise ou non (bien sûr, cela renforce le premier point ; notamment, les premières versions de Java utilisaient la préemption de priorité sur les implémentations Solaris et le découpage du temps dans Windows. Parce que la plupart des programmeurs ne comprenaient pas et se plaignaient que "le threading ne fonctionne pas dans Solaris" ils ont changé le modèle en tranches de temps partout). Quoi qu'il en soit, l'essentiel est que le découpage temporel crée des changements de contexte supplémentaires (et potentiellement inutiles). Chaque changement de contexte prend du temps CPU, et ce temps est effectivement supprimé du travail qui peut être fait sur le vrai travail à accomplir. Cependant, le temps investi dans le changement de contexte en raison du découpage en temps ne devrait pas dépasser un très faible pourcentage du temps global, à moins que quelque chose d'assez étrange ne se produise, et il n'y a aucune raison pour que je m'attende à ce que ce soit le cas dans un serveur Web simple). Donc, oui, les changements de contexte excessifs impliqués dans le découpage du temps sont inefficaces (et cela ne se produit pas dans et ce temps est effectivement supprimé du travail qui peut être fait sur le vrai travail à accomplir. Cependant, le temps investi dans le changement de contexte en raison du découpage en temps ne devrait pas dépasser un très faible pourcentage du temps global, à moins que quelque chose d'assez étrange ne se produise, et il n'y a aucune raison pour que je m'attende à ce que ce soit le cas dans un serveur Web simple). Donc, oui, les changements de contexte excessifs impliqués dans le découpage du temps sont inefficaces (et cela ne se produit pas dans et ce temps est effectivement supprimé du travail qui peut être fait sur le vrai travail à accomplir. Cependant, le temps investi dans le changement de contexte en raison du découpage en temps ne devrait pas dépasser un très faible pourcentage du temps global, à moins que quelque chose d'assez étrange ne se produise, et il n'y a aucune raison pour que je m'attende à ce que ce soit le cas dans un serveur Web simple). Donc, oui, les changements de contexte excessifs impliqués dans le découpage du temps sont inefficaces (et cela ne se produit pas dansthreads du noyau en règle générale, btw), mais la différence sera de quelques pour cent du débit, et non du type de facteurs de nombre entier qui sont impliqués dans les revendications de performances qui sont souvent impliquées pour Node.
Quoi qu'il en soit, toutes mes excuses pour tout cela étant long et variable, mais je pense vraiment que jusqu'à présent, la discussion n'a rien prouvé, et je serais heureux d'entendre quelqu'un dans l'une ou l'autre de ces situations:
a) une véritable explication de la raison pour laquelle Node devrait être meilleur (au-delà des deux scénarios que j'ai décrits ci-dessus, dont le premier (mauvais réglage) je pense est la vraie explication de tous les tests que j'ai vus jusqu'à présent. ], en fait, plus j'y pense, plus je me demande si la mémoire utilisée par un grand nombre de piles peut être importante ici. Les tailles de pile par défaut pour les threads modernes ont tendance à être assez énormes, mais la mémoire allouée par un système d'événement basé sur la fermeture ne serait que ce qui est nécessaire)
b) une véritable référence qui donne en fait une chance équitable au serveur fileté de choix. Au moins de cette façon, je devrais cesser de croire que les affirmations sont essentiellement fausses;> ([modifier] c'est probablement plus fort que je ne le pensais, mais je pense que les explications données pour les avantages de performance sont au mieux incomplètes, et la les repères indiqués ne sont pas raisonnables).
À la vôtre, Toby
select()
est plus rapide que les échanges de contexte de thread.