portaldacalheta.pt
  • Principal
  • Gestion De L'ingénierie
  • Gestion De Projet
  • Autre
  • Les Tendances
Back-End

Performances d'E / S côté serveur: Node vs PHP vs Java vs Go



Comprendre le modèle d'entrée / sortie (E / S) de votre application peut faire la différence entre une application qui gère la charge à laquelle elle est soumise et une qui s'effondre face à des cas d'utilisation réels. Peut-être que si votre application est petite et ne dessert pas des charges élevées, cela peut avoir beaucoup moins d'importance. Mais à mesure que la charge de trafic de votre application augmente, travailler avec le mauvais modèle d'E / S peut vous plonger dans un monde de souffrance.

Et comme dans la plupart des situations où plusieurs approches sont possibles, il ne s’agit pas seulement de savoir laquelle est la meilleure, il s’agit de comprendre les compromis. Promenons-nous dans le paysage des E / S et voyons ce que nous pouvons espionner.



Dans cet article, nous comparerons Node, Java, Go et PHP avec Apache, discuterons de la manière dont les différents langages modélisent leurs E / S, des avantages et des inconvénients de chaque modèle, et conclurons avec quelques points de repère rudimentaires. Si vous êtes préoccupé par les performances d'E / S de votre prochaine application Web, cet article est pour vous.



Principes de base des E / S: un rappel rapide

Pour comprendre les facteurs impliqués dans les E / S, nous devons d'abord revoir les concepts au niveau du système d'exploitation. S'il est peu probable que vous ayez à gérer directement nombre de ces concepts, vous les gérez indirectement via l'environnement d'exécution de votre application en permanence. Et les détails comptent.



Appels système

Premièrement, nous avons des appels système, qui peuvent être décrits comme suit:

  • Votre programme (dans «user land», comme on dit) doit demander au noyau du système d'exploitation d'effectuer une opération d'E / S en son nom.
  • Un «appel système» est le moyen par lequel votre programme demande au noyau de faire quelque chose. Les spécificités de la façon dont cela est implémenté varient d'un système d'exploitation à l'autre, mais le concept de base est le même. Il va y avoir des instructions spécifiques qui transfèrent le contrôle de votre programme vers le noyau (comme un appel de fonction mais avec une sauce spéciale spécifiquement pour traiter cette situation). De manière générale, les appels système sont bloquants, ce qui signifie que votre programme attend que le noyau revienne à votre code.
  • Le noyau effectue l'opération d'E / S sous-jacente sur le périphérique physique en question (disque, carte réseau, etc.) et répond à l'appel système. Dans le monde réel, le noyau peut avoir à faire un certain nombre de choses pour répondre à votre demande, y compris attendre que l'appareil soit prêt, mettre à jour son état interne, etc., mais en tant que développeur d'applications, vous ne vous souciez pas de cela. C’est le travail du noyau.

Diagramme des appels système



Appels bloquants et non bloquants

Maintenant, je viens de dire ci-dessus que les appels système bloquent, et c'est vrai dans un sens général. Cependant, certains appels sont classés comme «non bloquants», ce qui signifie que le noyau prend votre requête, la met dans la file d'attente ou la mémoire tampon quelque part, puis revient immédiatement sans attendre que les E / S réelles se produisent. Ainsi, il ne «bloque» que pendant une très courte période, juste assez longtemps pour mettre votre demande en file d'attente.

Quelques exemples (d'appels système Linux) pourraient aider à clarifier: - read() est un appel bloquant - vous lui passez une poignée indiquant quel fichier et une mémoire tampon où fournir les données qu'il lit, et l'appel revient lorsque les données sont là. Notez que cela a l'avantage d'être simple et agréable. - epoll_create(), epoll_ctl() et epoll_wait() sont des appels qui, respectivement, vous permettent de créer un groupe de poignées pour écouter, d'ajouter / supprimer des gestionnaires de ce groupe, puis de bloquer jusqu'à ce qu'il y ait une activité. Cela vous permet de contrôler efficacement un grand nombre d'opérations d'E / S avec un seul thread, mais je prends de l'avance sur moi-même. C'est parfait si vous avez besoin de la fonctionnalité, mais comme vous pouvez le voir, c'est certainement plus complexe à utiliser.



Il est important de comprendre ici l’ordre de grandeur des différences de timing. Si un cœur de processeur fonctionne à 3 GHz, sans entrer dans les optimisations que le processeur peut faire, il effectue 3 milliards de cycles par seconde (ou 3 cycles par nanoseconde). Un appel système non bloquant peut prendre de l'ordre de 10 s de cycles pour se terminer - ou «quelques nanosecondes». Un appel qui bloque la réception d’informations sur le réseau peut prendre beaucoup plus de temps, par exemple 200 millisecondes (1/5 de seconde). Et disons, par exemple, que l’appel non bloquant a pris 20 nanosecondes et que l’appel de blocage a pris 200 000 000 de nanosecondes. Votre processus a juste attendu 10 millions de fois plus longtemps pour l'appel de blocage.

Appels système bloquants ou non bloquants



Le noyau fournit les moyens d'effectuer à la fois des E / S bloquantes («lire à partir de cette connexion réseau et me donner les données») et des E / S non bloquantes («dites-moi quand l'une de ces connexions réseau a de nouvelles données»). Et quel mécanisme est utilisé bloquera le processus d'appel pendant des durées radicalement différentes.

Planification

La troisième chose essentielle à suivre est ce qui se passe lorsque de nombreux threads ou processus commencent à se bloquer.



Pour nos besoins, il n'y a pas une énorme différence entre un thread et un processus. Dans la vraie vie, la différence la plus notable liée aux performances est que, comme les threads partagent la même mémoire et que les processus ont chacun leur propre espace mémoire, la création de processus séparés a tendance à prendre beaucoup plus de mémoire. Mais quand nous parlons de planification, cela se résume vraiment à une liste de choses (threads et processus) dont chacun a besoin pour obtenir une tranche de temps d'exécution sur les cœurs de processeur disponibles. Si vous avez 300 threads en cours d'exécution et 8 cœurs sur lesquels les exécuter, vous devez diviser le temps afin que chacun ait sa part, chaque noyau fonctionnant pendant une courte période de temps, puis passant au thread suivant. Cela se fait via un «changement de contexte», faisant passer le processeur d'un thread / processus à l'autre.

Ces changements de contexte ont un coût qui leur est associé - ils prennent un certain temps. Dans certains cas rapides, cela peut être inférieur à 100 nanosecondes, mais il n'est pas rare que cela prenne 1000 nanosecondes ou plus en fonction des détails de mise en œuvre, de la vitesse / de l'architecture du processeur, du cache du processeur, etc.



Et plus il y a de threads (ou de processus), plus il y a de changement de contexte. Lorsque nous parlons de milliers de threads et de centaines de nanosecondes pour chacun, les choses peuvent devenir très lentes.

Cependant, les appels non bloquants indiquent essentiellement au noyau 'ne m'appelez que lorsque vous avez de nouvelles données ou un événement sur l'une de ces connexions.' Ces appels non bloquants sont conçus pour gérer efficacement des charges d'E / S importantes et réduire le changement de contexte.

Avec moi si loin? Parce que vient maintenant la partie amusante: regardons ce que certains langages populaires font avec ces outils et tirons quelques conclusions sur les compromis entre la facilité d'utilisation et les performances… et d'autres informations intéressantes.

À noter, alors que les exemples présentés dans cet article sont triviaux (et partiels, avec uniquement les bits pertinents affichés); l'accès à la base de données, les systèmes de mise en cache externes (memcache, etc.) et tout ce qui nécessite des E / S va finir par effectuer une sorte d'appel d'E / S sous le capot qui aura le même effet que les exemples simples présentés. De plus, pour les scénarios où les E / S sont décrites comme «bloquantes» (PHP, Java), les lectures et écritures de requête et de réponse HTTP sont elles-mêmes des appels bloquants: encore une fois, plus d'E / S cachées dans le système avec ses problèmes de performances associés prendre en compte.

De nombreux facteurs entrent en jeu dans le choix d'un langage de programmation pour un projet. Il existe même de nombreux facteurs lorsque vous ne considérez que les performances. Mais, si vous craignez que votre programme soit principalement limité par les E / S, si les performances d'E / S sont décisives pour votre projet, ce sont des choses que vous devez savoir.

L'approche «Keep It Simple»: PHP

Dans les années 90, beaucoup de gens portaient Converser chaussures et écriture de scripts CGI en Perl. Ensuite, PHP est arrivé et, même si certaines personnes aiment s'y attarder, cela a beaucoup facilité la création de pages Web dynamiques.

Lequel des principes de la Gestalt déclare que nous avons tendance à percevoir les objets en groupe ?

Le modèle utilisé par PHP est assez simple. Il existe quelques variantes, mais votre serveur PHP moyen ressemble à:

Une requête HTTP arrive du navigateur d'un utilisateur et atteint votre serveur Web Apache. Apache crée un processus distinct pour chaque requête, avec quelques optimisations pour les réutiliser afin de minimiser le nombre de processus à effectuer (la création de processus est, relativement parlant, lente). Apache appelle PHP et lui dit d'exécuter le .php approprié. fichier sur le disque. Le code PHP s'exécute et bloque les appels d'E / S. Vous appelez file_get_contents() en PHP et sous le capot, cela fait read() syscalls et attend les résultats.

Et bien sûr, le code réel est simplement intégré directement dans votre page, et les opérations sont bloquantes:

query('SELECT id, data FROM examples ORDER BY id DESC limit 100'); ?>

En termes d'intégration avec le système, c'est comme suit:

Modèle d

Assez simple: un processus par demande. Les appels d'E / S se bloquent simplement. Avantage? C’est simple et cela fonctionne. Désavantage? Frappez-le avec 20000 clients simultanément et votre serveur s'enflammera. Cette approche ne s'adapte pas bien car les outils fournis par le noyau pour traiter les E / S à volume élevé (epoll, etc.) ne sont pas utilisés. Et pour ajouter l'insulte à la blessure, l'exécution d'un processus distinct pour chaque demande a tendance à utiliser beaucoup de ressources système, en particulier la mémoire, qui est souvent la première chose dont vous manquez dans un scénario comme celui-ci.

Remarque: L'approche utilisée pour Ruby est très similaire à celle de PHP, et d'une manière large, générale et ondulée, elle peut être considérée comme la même pour nos besoins.

L'approche multithread: Java

Donc Java arrive, juste au moment où vous avez acheté votre premier nom de domaine et c'était cool de dire au hasard 'dot com' après une phrase. Et Java a le multithreading intégré au langage, ce qui (surtout quand il a été créé) est assez génial.

La plupart des serveurs Web Java fonctionnent en démarrant un nouveau thread d'exécution pour chaque requête qui arrive, puis en appelant éventuellement la fonction que vous, en tant que développeur de l'application, avez écrite.

Les E / S dans un servlet Java ont tendance à ressembler à ceci:

public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // blocking file I/O InputStream fileIs = new FileInputStream('/path/to/file'); // blocking network I/O URLConnection urlConnection = (new URL('http://example.com/example-microservice')).openConnection(); InputStream netIs = urlConnection.getInputStream(); // some more blocking network I/O out.println('...'); }

Depuis notre doGet ci-dessus correspond à une demande et est exécutée dans son propre thread, au lieu d'un processus séparé pour chaque demande qui nécessite sa propre mémoire, nous avons un thread séparé. Cela a quelques avantages intéressants, comme pouvoir partager l'état, les données en cache, etc. entre les threads car ils peuvent accéder à la mémoire de l'autre, mais l'impact sur la façon dont il interagit avec le calendrier est toujours presque identique à ce qui est fait dans le PHP exemple précédemment. Chaque demande obtient un nouveau thread et les diverses opérations d'E / S se bloquent à l'intérieur de ce thread jusqu'à ce que la demande soit entièrement traitée. Les threads sont regroupés pour minimiser le coût de leur création et de leur destruction, mais des milliers de connexions signifient des milliers de threads, ce qui est mauvais pour le planificateur.

Un jalon important est que dans la version 1.4, Java (et une mise à jour significative à nouveau dans la 1.7) a acquis la possibilité de faire des appels d'E / S non bloquants. La plupart des applications, Web et autres, ne l’utilisent pas, mais au moins elles sont disponibles. Certains serveurs Web Java essaient d'en tirer profit de différentes manières; cependant, la grande majorité des applications Java déployées fonctionnent toujours comme décrit ci-dessus.

Modèle d

Java nous rapproche et a certainement de bonnes fonctionnalités prêtes à l'emploi pour les E / S, mais cela ne résout toujours pas vraiment le problème de ce qui se passe lorsque vous avez une application fortement liée aux E / S qui se fait pilonner le sol avec plusieurs milliers de fils bloquants.

E / S non bloquantes en tant que citoyen de première classe: Node

Node.js. est le gamin le plus populaire pour améliorer les E / S. Quiconque a eu la plus brève introduction à Node a appris qu'il était «non bloquant» et qu'il gère efficacement les E / S. Et cela est vrai dans un sens général. Mais le diable est dans les détails et les moyens par lesquels cette sorcellerie a été réalisée comptent quand il s'agit de performances.

Essentiellement, le changement de paradigme implémenté par Node est qu'au lieu de dire essentiellement «écrivez votre code ici pour gérer la demande», ils disent plutôt «écrivez le code ici pour commencer à gérer la demande». Chaque fois que vous avez besoin de faire quelque chose qui implique des E / S, vous faites la demande et donnez une fonction de rappel que Node appellera quand elle sera terminée.

Le code de nœud typique pour effectuer une opération d'E / S dans une demande se présente comme suit:

http.createServer(function(request, response) { fs.readFile('/path/to/file', 'utf8', function(err, data) { response.end(data); }); });

Comme vous pouvez le voir, il y a deux fonctions de rappel ici. Le premier est appelé quand une demande démarre, et le second est appelé lorsque les données du fichier sont disponibles.

Cela donne essentiellement à Node la possibilité de gérer efficacement les E / S entre ces rappels. Un scénario où cela serait encore plus pertinent est celui où vous effectuez un appel de base de données dans Node, mais je ne me soucierai pas de l'exemple car c'est exactement le même principe: vous démarrez l'appel de base de données et donnez à Node une fonction de rappel, il effectue les opérations d'E / S séparément à l'aide d'appels non bloquants, puis appelle votre fonction de rappel lorsque les données que vous avez demandées sont disponibles. Ce mécanisme consistant à mettre en file d'attente les appels d'E / S et à laisser Node le gérer, puis à obtenir un rappel, est appelé «Boucle d'événement». Et ça marche plutôt bien.

Modèle d

Il y a cependant un hic à ce modèle. Sous le capot, la raison en est beaucoup plus liée à la mise en œuvre du moteur JavaScript V8 (le moteur JS de Chrome utilisé par Node). un qu'autre chose. Le code JS que vous écrivez s'exécute tous dans un seul thread. Penses-y un moment. Cela signifie que, bien que les E / S soient effectuées à l'aide de techniques efficaces non bloquantes, votre JS peut qui effectue des opérations liées au processeur s'exécute dans un seul thread, chaque morceau de code bloquant le suivant. Un exemple courant où cela pourrait se produire est la boucle sur les enregistrements de la base de données pour les traiter d'une manière ou d'une autre avant de les envoyer au client. Voici un exemple qui montre comment cela fonctionne:

var handler = function(request, response) { connection.query('SELECT ...', function (err, rows) { if (err) { throw err }; for (var i = 0; i

Alors que Node gère efficacement les E / S, cela for loop dans l'exemple ci-dessus utilise des cycles CPU dans votre seul et unique thread principal. Cela signifie que si vous avez 10 000 connexions, cette boucle peut amener l'intégralité de votre application à une analyse, en fonction du temps nécessaire. Chaque demande doit partager une tranche de temps, une à la fois, dans votre fil de discussion principal.

Le principe sur lequel tout ce concept est basé est que les opérations d'E / S sont la partie la plus lente, il est donc très important de les gérer efficacement, même si cela signifie effectuer d'autres traitements en série. Cela est vrai dans certains cas, mais pas dans tous.

L'autre point est que, et bien que ce ne soit qu'une opinion, il peut être assez fastidieux d'écrire un tas de rappels imbriqués et certains soutiennent que cela rend le code beaucoup plus difficile à suivre. Il n’est pas rare de voir des rappels imbriqués à quatre, cinq niveaux ou même plus dans le code Node.

Nous sommes de retour aux compromis. Le modèle Node fonctionne bien si votre principal problème de performances est les E / S. Cependant, son talon d'Achille est que vous pouvez entrer dans une fonction qui gère une requête HTTP et mettre du code gourmand en CPU et amener chaque connexion à une analyse si vous ne faites pas attention.

comment utiliser un bot dans discord

Naturellement non bloquant: Allez

Avant d’entrer dans la section consacrée à Go, il m’appartient de révéler que je suis un fan de Go. Je l’ai utilisé pour de nombreux projets et je suis ouvertement partisan de ses avantages en matière de productivité, et je les vois dans mon travail lorsque je l’utilise.

Cela dit, voyons comment il traite les E / S. Une caractéristique clé du langage Go est qu'il contient son propre planificateur. Au lieu de chaque thread d'exécution correspondant à un seul thread OS, il fonctionne avec le concept de «goroutines». Et le runtime Go peut affecter un goroutine à un thread OS et le faire exécuter, ou le suspendre et ne pas l'associer à un thread OS, en fonction de ce que fait ce goroutine. Chaque requête provenant du serveur HTTP de Go est traitée dans une Goroutine distincte.

Le diagramme du fonctionnement du planificateur ressemble à ceci:

Modèle d

Sous le capot, ceci est implémenté par divers points dans le runtime Go qui implémentent l'appel d'E / S en faisant la demande d'écriture / lecture / connexion / etc., Mettez le goroutine actuel en veille, avec les informations pour réveiller le goroutine lorsque des mesures supplémentaires peuvent être prises.

En effet, le runtime Go fait quelque chose qui n'est pas très différent de ce que fait Node, sauf que le mécanisme de rappel est intégré à l'implémentation de l'appel d'E / S et interagit automatiquement avec le planificateur. Il ne souffre pas non plus de la restriction d'avoir à exécuter tout le code de votre gestionnaire dans le même thread, Go mappera automatiquement vos Goroutines à autant de threads du système d'exploitation qu'il jugera approprié en fonction de la logique de son planificateur. Le résultat est un code comme celui-ci:

à quoi ça sert
func ServeHTTP(w http.ResponseWriter, r *http.Request) { // the underlying network call here is non-blocking rows, err := db.Query('SELECT ...') for _, row := range rows { // do something with the rows, // each request in its own goroutine } w.Write(...) // write the response, also non-blocking }

Comme vous pouvez le voir ci-dessus, la structure de code de base de ce que nous faisons ressemble à celle des approches plus simplistes, tout en réalisant des E / S non bloquantes sous le capot.

Dans la plupart des cas, cela finit par être «le meilleur des deux mondes». Les E / S non bloquantes sont utilisées pour toutes les choses importantes, mais votre code semble bloquant et a donc tendance à être plus simple à comprendre et à maintenir. L'interaction entre le planificateur Go et le planificateur du système d'exploitation gère le reste. Ce n’est pas une magie complète, et si vous construisez un grand système, il vaut la peine de prendre le temps de comprendre plus en détail son fonctionnement; mais en même temps, l'environnement que vous obtenez «prêt à l'emploi» fonctionne et s'adapte assez bien.

Go a peut-être ses défauts, mais en général, la façon dont il gère les E / S n'en fait pas partie.

Mensonges, mensonges damnés et repères

Il est difficile de donner des timings exacts sur le changement de contexte impliqué avec ces différents modèles. Je pourrais également dire que cela vous est moins utile. Au lieu de cela, je vais vous donner quelques points de repère de base qui comparent les performances globales du serveur HTTP de ces environnements de serveur. Gardez à l'esprit que de nombreux facteurs sont impliqués dans les performances de l'ensemble du chemin de requête / réponse HTTP de bout en bout, et les chiffres présentés ici ne sont que quelques exemples que j'ai rassemblés pour donner une comparaison de base.

Pour chacun de ces environnements, j'ai écrit le code approprié à lire dans un fichier de 64 Ko avec des octets aléatoires, j'ai exécuté un hachage SHA-256 dessus N nombre de fois (N étant spécifié dans la chaîne de requête de l'URL, par exemple, .../test.php?n=100 ) et imprimez le hachage résultant en hexadécimal. J'ai choisi cela car c'est un moyen très simple d'exécuter les mêmes tests avec des E / S cohérentes et une manière contrôlée d'augmenter l'utilisation du processeur.

Voir ces notes de référence pour un peu plus de détails sur les environnements utilisés.

Tout d'abord, examinons quelques exemples de faible concurrence. L'exécution de 2000 itérations avec 300 requêtes simultanées et un seul hachage par requête (N = 1) nous donne ceci:

Nombre moyen de millisecondes pour terminer une demande sur toutes les demandes simultanées, N = 1

Les durées sont le nombre moyen de millisecondes pour terminer une demande sur toutes les demandes simultanées. Plus bas c'est mieux.

Il est difficile de tirer une conclusion à partir de ce seul graphe, mais cela me semble qu'à ce volume de connexion et de calcul, nous voyons des moments qui ont plus à voir avec l'exécution générale des langages eux-mêmes, beaucoup plus que le E / S. Notez que les langages qui sont considérés comme des «langages de script» (typage lâche, interprétation dynamique) sont les plus lents.

Mais que se passe-t-il si nous augmentons N à 1000, toujours avec 300 requêtes simultanées - la même charge mais 100x plus d'itérations de hachage (beaucoup plus de charge du processeur):

Nombre moyen de millisecondes pour terminer une demande sur toutes les demandes simultanées, N = 1000

Les durées sont le nombre moyen de millisecondes pour terminer une demande sur toutes les demandes simultanées. Plus bas c'est mieux.

Tout à coup, les performances des nœuds diminuent considérablement, car les opérations gourmandes en ressources processeur de chaque requête se bloquent mutuellement. Et il est intéressant de noter que les performances de PHP s’améliorent beaucoup (par rapport aux autres) et surpassent Java dans ce test. (Il est intéressant de noter qu'en PHP, l'implémentation SHA-256 est écrite en C et que le chemin d'exécution passe beaucoup plus de temps dans cette boucle, puisque nous faisons maintenant 1000 itérations de hachage).

Essayons maintenant 5000 connexions simultanées (avec N = 1) - ou aussi près que possible. Malheureusement, pour la plupart de ces environnements, le taux d'échec n'était pas négligeable. Pour ce graphique, nous examinerons le nombre total de demandes par seconde. Le plus haut sera le mieux :

Nombre total de requêtes par seconde, N = 1, 5000 req / s

Nombre total de requêtes par seconde. Plus c'est mieux.

Et l'image est assez différente. C’est une supposition, mais il semble qu’à un volume de connexion élevé, la surcharge par connexion impliquée dans la création de nouveaux processus et la mémoire supplémentaire qui lui est associée dans PHP + Apache semble devenir un facteur dominant et optimise les performances de PHP. Clairement, Go est le gagnant ici, suivi de Java, Node et enfin PHP.

Bien que les facteurs impliqués dans votre débit global soient nombreux et varient considérablement d'une application à l'autre, plus vous comprendrez les tripes de ce qui se passe sous le capot et les compromis impliqués, mieux vous vous porterez.

En résumé

Avec tout ce qui précède, il est assez clair qu’au fur et à mesure que les langages ont évolué, les solutions pour gérer les applications à grande échelle qui effectuent de nombreuses E / S ont évolué avec lui.

Pour être juste, PHP et Java, malgré les descriptions de cet article, ont implémentations de E / S non bloquantes disponible pour utilisation dans des applications Web . Mais celles-ci ne sont pas aussi courantes que les approches décrites ci-dessus, et la surcharge opérationnelle associée à la maintenance des serveurs utilisant de telles approches devrait être prise en compte. Sans oublier que votre code doit être structuré de manière à fonctionner avec de tels environnements; votre application Web PHP ou Java «normale» ne fonctionnera généralement pas sans modifications importantes dans un tel environnement.

À titre de comparaison, si nous considérons quelques facteurs importants qui affectent les performances ainsi que la facilité d'utilisation, nous obtenons ceci:

Langue Threads vs processus E / S non bloquantes Facilité d'utilisation
PHP Processus Non
Java Fils Disponible Nécessite des rappels
Node.js Fils Oui Nécessite des rappels
Aller Fils (Goroutines) Oui Aucun rappel nécessaire


Les threads seront généralement beaucoup plus efficaces en mémoire que les processus, car ils partagent le même espace mémoire, contrairement aux processus. En combinant cela avec les facteurs liés aux E / S non bloquantes, nous pouvons voir qu'au moins avec les facteurs considérés ci-dessus, lorsque nous descendons dans la liste, la configuration générale en ce qui concerne les E / S s'améliore. Donc, si je devais choisir un gagnant dans le concours ci-dessus, ce serait certainement Go.

Néanmoins, dans la pratique, le choix d'un environnement dans lequel créer votre application est étroitement lié à la familiarité de votre équipe avec ledit environnement et à la productivité globale que vous pouvez atteindre avec celui-ci. Il n'est donc pas logique pour chaque équipe de se lancer et de commencer à développer des applications et des services Web dans Node ou Go. En effet, la recherche de développeurs ou la familiarité de votre équipe interne est souvent citée comme la principale raison pour ne pas utiliser un langage et / ou un environnement différents. Cela dit, les temps ont beaucoup changé au cours des quinze dernières années.

Espérons que ce qui précède vous aide à brosser un tableau plus clair de ce qui se passe sous le capot et vous donne quelques idées sur la façon de gérer l'évolutivité réelle de votre application. Bonne entrée et sortie!

Algorithmes de clustering: du début à l'état de l'art

Science Des Données Et Bases De Données

Algorithmes de clustering: du début à l'état de l'art
Manipulation ultime de la collecte de données en mémoire avec Supergroup.js

Manipulation ultime de la collecte de données en mémoire avec Supergroup.js

Science Des Données Et Bases De Données

Articles Populaires
Comment créer un bouton SSO - Un didacticiel de connexion Flask
Comment créer un bouton SSO - Un didacticiel de connexion Flask
Invalidation du cache Rails au niveau du champ: une solution DSL
Invalidation du cache Rails au niveau du champ: une solution DSL
Tirer le meilleur parti des actions - Leçons d'un ancien analyste de recherche
Tirer le meilleur parti des actions - Leçons d'un ancien analyste de recherche
Programmation visuelle avec Node-RED: câbler l'Internet des objets en toute simplicité
Programmation visuelle avec Node-RED: câbler l'Internet des objets en toute simplicité
SaaS - Tactiques de tarification qui peuvent catapulter votre entreprise
SaaS - Tactiques de tarification qui peuvent catapulter votre entreprise
 
Programmation visuelle avec Node-RED: câbler l'Internet des objets en toute simplicité
Programmation visuelle avec Node-RED: câbler l'Internet des objets en toute simplicité
Introduction à Kotlin: programmation Android pour les humains
Introduction à Kotlin: programmation Android pour les humains
Pourquoi les devises des marchés émergents sont-elles volatiles?
Pourquoi les devises des marchés émergents sont-elles volatiles?
Comment créer une application multi-locataire: un didacticiel de mise en veille prolongée
Comment créer une application multi-locataire: un didacticiel de mise en veille prolongée
Guide de migration d'Oracle vers SQL Server et SQL Server vers Oracle
Guide de migration d'Oracle vers SQL Server et SQL Server vers Oracle
Articles Populaires
  • comment obtenir un terminal bloomberg
  • qui rend compte au directeur financier
  • le processus consistant à tenter de créer de la richesse en démarrant une entreprise
  • la différence entre l'art et le design
  • Top 10 des vulnérabilités des applications Web
Catégories
  • Gestion De L'ingénierie
  • Gestion De Projet
  • Autre
  • Les Tendances
  • © 2022 | Tous Les Droits Sont Réservés

    portaldacalheta.pt