Pourquoi Ruby est lente? [fermé]
Ruby est lent à certaines choses. Mais quelles sont les parties les plus problématiques?
dans quelle mesure le ramasseur d'ordures affecte-t-il la performance? Je sais que j'ai eu des moments où courir seul le collecteur d'ordures a pris plusieurs secondes, surtout quand je travaillais avec les bibliothèques OpenGL.
j'ai utilisé des bibliothèques de maths matricielles avec Ruby qui étaient particulièrement lentes. Y a-t-il un problème avec la façon dont ruby implémente les mathématiques de base?
sont il y a-t-il des caractéristiques dynamiques dans Ruby qui ne peuvent tout simplement pas être mises en œuvre efficacement? Si oui, comment D'autres langues comme Lua et Python résolvent-elles ces problèmes?
y a-t-il eu des travaux récents qui ont considérablement amélioré le rendement?
9 réponses
Ruby est lent. Mais quelles sont les parties les plus problématiques?
Il ne "fin de recherche" pour les méthodes, pour permettre une certaine flexibilité. Cela ralentit un peu. Il doit aussi se souvenir des noms de variables par contexte pour permettre eval, donc ses trames et appels de méthode sont plus lents. En outre, il manque un bon compilateur JIT actuellement, bien que L'IRM 1.9 a un compilateur bytecode (qui est mieux), et jruby le compile vers le bas de java bytecode, qui puis (peut) compiler via le compilateur JIT du HotSpot JVM, mais il finit par être à peu près à la même vitesse que 1.9.
dans quelle mesure le collecteur d'ordures influe-t-il sur la performance? Je sais que j'ai eu des moments où courir seul le collecteur d'ordures a pris plusieurs secondes, surtout quand je travaillais avec les bibliothèques OpenGL.
de certains graphiques à http://www.igvita.com/2009/06/13/profiling-ruby-with-googles-perftools/ je dirais qu'il faut environ 10% ce qui est un peu--vous pouvez diminuer ce coup en augmentant le malloc_limit dans gc.c et recompilation.
j'ai utilisé des bibliothèques de maths matricielles avec Ruby qui étaient particulièrement lentes. Y a-t-il un problème avec la façon dont ruby implémente les mathématiques de base?
1.8 Ruby "didn't" implémenter les mathématiques de base il implémentait des classes numériques et vous appeliez des choses comme Fixnum#+ Fixnum# / une fois par appel--ce qui était lent. Ruby 1.9 trompe un peu en jouant dans les opérations de maths de base.
y a-t-il des caractéristiques dynamiques dans Ruby qui ne peuvent tout simplement pas être mises en œuvre efficacement? Si oui, comment D'autres langues comme Lua et Python résolvent-elles ces problèmes?
des choses comme eval sont difficiles à mettre en œuvre efficacement, bien que beaucoup de travail puisse être fait, je suis sûr. Le kicker pour Ruby est qu'il doit accueillir pour quelqu'un dans un autre fil changer la définition d'une classe spontanément, il doit être très conservateur.
y a-t-il eu des travaux récents qui ont considérablement amélioré le rendement?
1.9 est comme un 2x speedup. Il est également plus efficace de l'espace. JRuby essaie constamment d'améliorer sa vitesse [et passe probablement moins de temps au GC que KRI]. En plus, Je ne suis pas au courant de grand-chose, sauf de petits passe-temps que je travaille. sur. Notez aussi que les chaînes de 1.9 sont parfois plus lentes à cause de la convivialité de l'encodage.
Ruby est très bon pour fournir des solutions rapidement. Moins pour la livraison de solutions rapides. Cela dépend du genre de problème que vous essayez de résoudre. Je me souviens des discussions sur L'ancien forum MSBASIC de CompuServe au début des années 90: quand on m'a demandé ce qui était plus rapide pour le développement de Windows, VB ou C, la réponse habituelle était "VB, d'environ 6 mois".
dans sa forme IRM 1.8, Ruby est - relativement - lent à effectuer certains types de tâches de calcul intensif. Joli beaucoup de toute langue interprétée souffre de cette façon par rapport à la plupart des langues compilées.
les raisons sont multiples: certaines assez facilement adressables (la collecte primitive des ordures en 1.8, par exemple), d'autres moins.
1.9 aborde certaines des questions, bien qu'il faudra probablement un certain temps avant qu'elles ne deviennent généralement disponibles. Certaines des autres implémentations qui ciblent des durées d'exécution pré-existantes, JRuby, IronRuby, MagLev pour exemple, ont le potentiel d'être beaucoup plus rapide.
en ce qui concerne les performances mathématiques, Je ne serais pas surpris de voir un débit assez lent: il fait partie du prix à payer pour une précision arbitraire. Encore une fois, choisissez votre problème. J'ai résolu plus de 70 des projet Euler problèmes à Ruby avec presque aucune solution prenant plus d'une minute à courir. À quelle vitesse Avez-vous besoin pour fonctionner et à quelle vitesse en avez-vous besoin?
la partie la plus problématique est"tout le monde".
points Bonus si ce "tout le monde" n'a pas vraiment utilisé la langue, jamais.
sérieusement, 1.9 est beaucoup plus rapide et est maintenant sur le même pied que python, et jruby est plus rapide que jython.
collecteurs de déchets sont partout; par exemple, Java a un, et il est plus rapide que C++ sur la manipulation de mémoire dynamique. Ruby n'est pas bien adapté pour le nombre crunching; mais peu de langues sont, donc si vous avez pièces computationnelles intensives dans votre programme dans n'importe quelle langue, vous feriez mieux de les réécrire en C (Java est rapide avec les mathématiques en raison de ses types primitifs, mais il a payé cher pour eux, ils sont clairement #1 dans les parties les plus laides de la langue).
en ce qui concerne les fonctionnalités dynamiques: elles ne sont pas rapides, mais le code sans elles dans des langages statiques peut être encore plus lent; par exemple, java utiliserait une configuration XML au lieu de Ruby utilisant un DSL; et il serait probablement plus lent car L'analyse XML est coûteuse.
Hmm - j'ai travaillé sur un projet il y a quelques années où j'ai gratté le baril avec la performance de Ruby, et je ne suis pas sûr que beaucoup ait changé depuis. En ce moment, c'est caveat emptor - vous devez savoir ne pas faire certaines choses, et franchement jeux / applications en temps réel serait l'un d'eux (puisque vous mentionnez OpenGL).
le coupable du meurtre de la performance interactive est le collecteur d'ordures - d'autres ici mentionnent que Java et d'autres environnements ont la collecte des ordures aussi, mais Ruby doit arrêter le monde pour courir. C'est-à-dire, il doit arrêter d'exécuter votre programme, scanner chaque registre et pointeur de mémoire à partir de zéro, marquer la mémoire qui est encore en usage, et libérer le reste. Le processus ne peut pas être interrompu pendant que cela se produit, et comme vous l'avez peut-être remarqué, cela peut prendre des centaines de millisecondes.
sa fréquence et Sa durée d'exécution est proportionnel au nombre d'objets que vous créez et détruisez, mais à moins de désactiver complètement, vous n'avez aucun contrôle. D'après mon expérience, il y avait plusieurs stratégies insatisfaisantes pour lisser ma boucle D'animation de Ruby:
- GC.disable / GC.activez autour des boucles d'animation critiques et peut-être un CG opportuniste.départ pour le forcer à aller quand il ne peut pas faire de mal. (parce que ma plate-forme cible à l'époque était une machine de 64 Mo de Windows NT, cela a causé le système de manquer de mémoire de temps en temps. Mais fondamentalement, c'est un mauvais idée-sauf si vous pouvez pré-calculer combien de mémoire vous pourriez avoir besoin avant de faire cela, vous risquez l'épuisement de la mémoire)
- réduire le nombre d'objets que vous créez afin que le GC ait moins de travail à faire (réduit la fréquence / durée de son exécution)
- Réécrire votre animation en boucle dans C (un flic, mais celui que je suis allé avec!)
ces jours - ci, je verrais probablement aussi si JRuby fonctionnerait comme un autre temps d'exécution, car je je crois qu'il s'appuie sur le collecteur D'ordures plus sophistiqué de Java.
l'autre problème de performance majeur que j'ai trouvé est l'E/S de base lors de l'essai d'écrire un serveur TFTP à Ruby il y a un certain temps (oui, je choisis tous les meilleurs langages pour mes projets critiques de performance c'était juste une expérience). La boucle la plus simple et la plus serrée pour répondre simplement à un paquet UDP avec un autre, contenant le prochain morceau d'un fichier, doit avoir été environ 20 fois plus lente que la version c stock. Je on soupçonne qu'il pourrait y avoir eu quelques améliorations à y apporter à partir de L'utilisation D'IO de faible niveau (sysread, etc.).) mais la lenteur pourrait être simplement dans le fait qu'il n'y a pas de bas niveau byte type de données-chaque petite Lecture est copiée dans une chaîne. Ce n'est qu'une spéculation, Je n'ai pas poussé ce projet beaucoup plus loin, mais il m'a mis en garde de compter sur snappy I / O.
la vitesse principale augmentation récente qui a continué, bien que je ne suis pas entièrement à jour ici, est que la machine virtuelle la mise en œuvre a été refaite pour 1.9, résultant en une exécution de code plus rapide. Cependant Je ne pense pas que le GC a changé , et je suis presque sûr qu'il n'y a rien de nouveau sur le front des entrées/sorties. Mais je ne suis pas tout à fait au courant sur le Ruby bord-saignant donc quelqu'un d'autre pourrait vouloir contribuer ici.
Steve Dekorte: "écrire une calculatrice D'ensemble de Mandelbrot dans un langage de haut niveau, c'est comme essayer d'exécuter L'Indy 500 dans un bus."
http://www.dekorte.com/blog/blog.cgi?do=item&id=4047
je recommande d'apprendre divers outils afin d'utiliser le bon outil pour le travail. Faire des transformations de matrice pourrait être fait efficacement en utilisant L'API de haut niveau qui enroule autour des boucles serrées avec des calculs arithmétiques intensifs. Voir RubyInline gem pour un exemple d'intégration du code C ou C++ dans Ruby script.
il y a aussi le langage Io qui est beaucoup plus lent que Ruby, mais il rend efficacement les films en Pixar et surpasse le C brut sur l'arithmétique vectorielle en utilisant L'accélération SIMD.
je suppose que vous vous demandez," quelles techniques particulières de Ruby ont tendance à être lentes."
l'Un est l'instanciation d'objets. Si vous faites de grandes quantités de lui, vous voulez examiner les moyens (raisonnables) de réduire cela, comme l'utilisation du Flyweight pattern , même si l'utilisation de la mémoire n'est pas un problème. Dans une bibliothèque où je l'ai retravaillé pour ne pas créer beaucoup d'objets très similaires encore et encore, j'ai doublé la vitesse globale de la bibliothèque.
Ruby 1.9.1 est environ deux fois plus rapide que PHP, et un peu plus rapide que Perl, selon certains benchmarks.
(mise à Jour: Ma source est ce ( capture d'écran ). Je ne sais pas ce que sa source est bien.)
Ruby n'est pas lent. L'ancien 1.8 l'est, mais pas le rubis actuel.
Ruby est lent parce qu'il a été conçu pour optimiser l'expérience des programmeurs, pas le temps d'exécution du programme. La lenteur n'est qu'un symptôme de cette décision. Si vous préférez la performance au plaisir, vous devriez probablement utiliser un langage différent. Ruby n'est pas pour tout.
de l'OMI, les langages dynamiques sont tous lents en général. Ils font quelque chose en runtime que les langages statiques font en compilant le temps.
Vérification de la Syntaxe, de l'Interprétation et Comme le type de la vérification, de la conversion. c'est inévitable, donc ruby est plus lent que le c/c++/java, corrigez-moi si je me trompe.