De combien de mémoire avez-vous besoin en 2024 pour exécuter 1 million de tâches simultanées ?
(hez2010.github.io)Un programme capable de traiter 1 million de tâches simultanées a été exécuté avec les versions récentes de Rust, C#, Python, Go et Java, entre autres, afin de comparer leur efficacité mémoire.
C# (NativeAOT) et Rust ont montré la meilleure efficacité mémoire, tandis que Go a reçu une évaluation plus faible en raison d’une consommation mémoire plus élevée qu’attendu. Globalement, les performances de .NET et de Rust se sont distinguées, et Java (GraalVM) a affiché une amélioration surprenante.
Plus précisément, Rust a utilisé le moins de mémoire avec environ 29MB, suivi de C# NativeAOT avec environ 71MB. NodeJS a enregistré 232MB, Python 339MB. Go a montré un résultat décevant avec une utilisation mémoire relativement élevée de 753MB. Java (GraalVM) a affiché une nette amélioration avec 92MB.
10 commentaires
En regardant le code de benchmark, il semble que, dans les cas de Rust et de Python, on ne crée pas réellement des tâches concurrentes, mais seulement des objets
futurequi sont certes asynchrones, sans pour autant pouvoir s’exécuter en parallèle avec d’autres tâches. J’imagine que C# est peut-être dans un cas similaire. En revanche, le code Go est conçu pour créer des goroutines, c’est-à-dire des tâches disposant de leur propre call stack, etc. Je pense que c’est probablement ce qui explique pourquoi l’utilisation mémoire de Go ressort particulièrement dans le cas des 1 million d’instances.Pour défendre Go : avec Go, même s’il y a n’importe quelle bibliothèque dans une fonction lancée 1 million de fois, ça fonctionne. Il suffit de mettre
go. Dans d’autres langages fondés sur l’asynchrone, s’il y a au milieu une bibliothèque synchrone qui consomme un peu de temps, on se retrouve dans une situation folle où cela annule tous les avantages de l’asynchrone.Pour profiter à 100 % des avantages de l’asynchrone, il faut convertir en asynchrone toutes les fonctions qui prennent ne serait-ce qu’un peu de temps.
Les VirtualThread de Java… hum. Cette fois, dans notre entreprise, on est partis en faisant confiance aux VirtualThread de Java, mais à cause de problèmes de compatibilité avec les bibliothèques, on a fini par revenir aux threads classiques, avec comme dénouement le lancement de plusieurs dizaines d’instances.
Pourriez-vous en dire un peu plus sur la partie compatibilité :eyes: ?
On peut dire qu’il n’y a plus vraiment lieu d’affirmer, comme on l’entend souvent dans l’écosystème Spring, que « pour utiliser correctement WebFlux, il faut révéler tout son potentiel avec R2DBC plutôt qu’avec JPA ».
J’ai entendu dire que la bibliothèque
msalde Microsoft ne fonctionne pas avec les virtual threadsJe pense que la bibliothèque
msalque vous avez donnée en exemple relève du même cas en Go également, si elle utilise des types de données ou des structures qui ne sont pas thread-safe.Quel rapport avec la thread safety ? Les goroutines ne sont de toute façon pas un système qui garantit la thread safety.
Merci pour ces informations
J’ai une question à vous poser.
Dans ce cas, pour les autres langages en dehors de Go, est-ce que tout casse dès qu’il y a une bibliothèque synchrone, comme vous l’avez expliqué ?
Ou bien existe-t-il aussi, parmi d’autres langages, des langages qui prennent en charge un asynchrone vraiment complet comme Go ?
Il existe l’expression « colorless ». Go est le seul langage où il n’est pas nécessaire de distinguer l’asynchrone du synchrone. Du point de vue de l’utilisateur, lorsqu’il s’agit de programmer avec des besoins de concurrence, Go a un avantage écrasant en termes de difficulté et d’ergonomie.
Les performances seront peut-être un peu en retrait par rapport à une programmation asynchrone optimisée, cela dit.
Désolé pour cette remarque, mais je vais seulement signaler les points erronés dans l’emploi des expressions « ça casse » et « asynchrone parfait ». Même en asynchrone, il est acceptable d’utiliser des bibliothèques synchrones, à condition qu’il y ait la garantie qu’elles se terminent en peu de temps. Le problème survient lorsqu’un appel synchrone a un temps d’exécution long, car cela retarde le traitement des autres tâches asynchrones. Avec Go, on peut allouer des tâches à des goroutines à l’échelle de centaines de millions, donc le langage lui-même n’a pas de concept d’asynchrone. Du point de vue de l’utilisateur, il est extrêmement pratique de pouvoir exécuter n’importe quelle fonction en parallèle simplement en la préfixant avec
go. Personnellement, je pense que l’asynchrone parfait est peut-être JavaScript, dont les fondements mêmes du langage sont asynchrones.