La version 3.3 du langage de programmation Ruby est disponible, elle intègre un nouvel analyseur "Prism" et un compilateur JIT purement Ruby.

Ruby 3.3 est une mise à jour importante de ce langage de programmation open-source dynamique. Ruby 3.3 intègre l'analyseur Prism ainsi qu'un nouveau compilateur juste à temps (JIT) purement Ruby.

Ruby 3.3 apporte avec lui l'analyseur Prism, un analyseur de descente récursive portable, tolérant aux erreurs et facile à maintenir. Prism est considéré comme prêt pour la production et peut être utilisé dès maintenant à la place de l'analyseur Ripper.

Ruby 3.3 ajoute également RJIT en tant que compilateur purement Ruby pour remplacer MJIT. Pour l'instant, RJIT ne supporte que x86_64 sur les architectures de type Unix et n'est considéré que comme expérimental. Bien que RJIT soit intéressant, il n'est pas encore prêt pour la production et il est recommandé aux utilisateurs d'utiliser le compilateur YJIT. Avec cette version 3.3 de Ruby, YJIT a reçu de nombreuses améliorations en termes de performances, d'utilisation de la mémoire et d'autres améliorations qui rendent ce compilateur JIT bien meilleur que les versions précédentes.

Ruby 3.3 utilise également Lrama comme générateur d'analyseur syntaxique en remplacement de Bison, le planificateur de threads M:N a été introduit, et il y a une variété d'autres améliorations de performance telles que le ramasse-miettes de Ruby.


Sortie de Ruby 3.3.0

Nous avons le plaisir d'annoncer la sortie de Ruby 3.3.0. Ruby 3.3 ajoute un nouvel analyseur nommé Prism, utilise Lrama comme générateur d'analyseur, ajoute un nouveau compilateur JIT pur-Ruby nommé RJIT, et de nombreuses améliorations de performance, en particulier YJIT.

Prism

  • Introduction de l'analyseur Prism comme gem par défaut
    • Prism est un analyseur de descente récursive portable, tolérant aux erreurs et maintenable pour le langage Ruby.

  • Prism est prêt pour la production et activement maintenu, vous pouvez l'utiliser à la place de Ripper
    • Il existe une documentation complète sur l'utilisation de Prism.
    • Prism est à la fois une bibliothèque C qui sera utilisée en interne par CRuby et une gem Ruby qui peut être utilisée par n'importe quel outil qui a besoin d'analyser du code Ruby.
    • Les méthodes notables de l'API Prism sont :
      • Prism.parse(source) qui retourne l'AST en tant que partie d'un objet de résultat d'analyse.
      • Prism.parse_comments(source) qui retourne les commentaires
      • Prism.parse_success ?(source) qui retourne vrai s'il n'y a pas d'erreurs.

  • Vous pouvez faire des pull requests ou des issues directement sur le dépôt Prism pour contribuer.

  • Vous pouvez maintenant utiliser ruby --parser=prism ou RUBYOPT="--parser=prism" pour expérimenter le compilateur Prism. À noter que ce drapeau n'est utilisé que pour le débogage.


Utilisation de Lrama au lieu de Bison

  • Remplacement de Bison par le générateur d'analyseur LALR de Lrama
    • Si vous êtes intéressé, veuillez consulter La vision future de l'analyseur Ruby
    • L'analyseur interne de Lrama est remplacé par l'analyseur LR généré par Racc pour des raisons de maintenabilité.
    • Les règles de paramétrage ( ?, *, +) sont supportées, elles seront utilisées dans Ruby parse.y


YJIT

  • Améliorations majeures des performances par rapport à Ruby 3.2
    • La prise en charge des arguments splat et rest a été améliorée.
    • Des registres sont alloués pour les opérations de pile de la machine virtuelle.
    • Plus d'appels avec des arguments optionnels sont compilés. Les gestionnaires d'exception sont également compilés.
    • Les types d'appels non pris en charge et les sites d'appels mégamorphiques ne sortent plus vers l'interpréteur.
    • Les méthodes de base comme Rails #blank? et les méthodes spécialisées #present? sont intégrées.
    • Integer#*, Integer#!=, String#!=, String#getbyte, Kernel#block_given?, Kernel#is_a?, Kernel#instance_of?, et Module#=== sont spécialement optimisés.
    • La vitesse de compilation est désormais légèrement supérieure à celle de Ruby 3.2.
    • Plus de 3 fois plus rapide que l'interpréteur sur Optcarrot !

  • Utilisation de la mémoire considérablement améliorée par rapport à Ruby 3.2
    • Les métadonnées du code compilé utilisent beaucoup moins de mémoire.
    • --yjit-call-threshold est automatiquement augmenté de 30 à 120 lorsque l'application a plus de 40 000 ISEQs.
    • --yjit-cold-threshold est ajouté pour ne pas compiler les ISEQs froides.
    • Un code plus compact est généré sur Arm64.

  • Le GC du code est maintenant désactivé par défaut
    • --yjit-exec-mem-size est traité comme une limite stricte où la compilation du nouveau code s'arrête.
    • Pas de chute soudaine des performances due au GC de code. Meilleur comportement du copy-on-write sur les serveurs reforking avec Pitchfork.
    • Vous pouvez toujours activer le GC de code si vous le souhaitez avec --yjit-code-gc

  • Ajout de RubyVM::YJIT.enable qui permet d'activer YJIT à l'exécution.
    • Vous pouvez démarrer YJIT sans modifier les arguments de la ligne de commande ou les variables d'environnement. Rails 7.2 activera YJIT par défaut en utilisant cette méthode.
    • Cela peut aussi être utilisé pour activer YJIT seulement une fois que votre application a fini de démarrer. --yjit-disable peut être utilisé si vous souhaitez utiliser d'autres options YJIT tout en désactivant YJIT au démarrage.

  • D'autres statistiques YJIT sont disponibles par défaut
    • yjit_alloc_size et plusieurs autres statistiques liées aux métadonnées sont maintenant disponibles par défaut.
      La statistique ratio_in_yjit produite par --yjit-stats est maintenant disponible dans les versions release, une version spéciale stats ou dev n'est plus nécessaire pour accéder à la plupart des statistiques.

  • Ajout de capacités de profilage
    • --yjit-perf est ajouté pour faciliter le profilage avec Linux perf.
    • --yjit-trace-exits supporte maintenant l'échantillonnage avec --yjit-trace-exits-sample-rate=N

  • Tests plus approfondis et corrections de bogues multiples


RJIT

  • Introduction d'un compilateur JIT purement Ruby, RJIT, qui remplace MJIT.
    • RJIT ne supporte que l'architecture x86-64 sur les plateformes Unix.
    • Contrairement à MJIT, il ne nécessite pas de compilateur C à l'exécution.

  • RJIT n'existe qu'à des fins expérimentales.
    • Vous devriez continuer à utiliser YJIT en production.

  • Si vous êtes intéressé par le développement de JIT pour Ruby, vous pouvez consulter la présentation de k0kubun lors de la troisième journée de RubyKaigi.


Planificateur de threads M:N

  • Le planificateur de threads M:N a été introduit.

    • M threads Ruby sont gérés par N threads natifs (threads OS), ce qui réduit les coûts de création et de gestion des threads.

    • La compatibilité avec l'extension C peut être rompue, de sorte que le planificateur de threads M:N est désactivé par défaut sur le Ractor principal.
      • La variable d'environnement RUBY_MN_THREADS=1 active les threads M:N sur le Ractor principal.
      • Les threads M:N sont toujours activés sur les Ractors non principaux.

    • La variable d'environnement RUBY_MAX_CPU=n définit le nombre maximum de N (nombre maximum de threads natifs). La valeur par défaut est 8.

      • Comme un seul thread Ruby par Ractor peut fonctionner en même temps, le nombre de threads natifs utilisé sera le plus petit entre le nombre spécifié dans RUBY_MAX_CPU et le nombre de Ractors en cours d'exécution. Ainsi, les applications à un seul Ractor (la plupart des applications) n'utiliseront qu'un seul thread natif.
      • Pour prendre en charge les opérations de blocage, plus de N threads natifs peuvent être utilisés.


Amélioration des performances

  • defined ?(@ivar) est optimisé avec les formes d'objets.

  • La résolution de nom telle que Socket.getaddrinfo peut maintenant être interrompue (dans les environnements où les pthreads sont disponibles).

  • Plusieurs améliorations de performance pour le Garbage Collector
    • Les jeunes objets référencés par d'anciens objets ne sont plus immédiatement promus à l'ancienne génération. Cela réduit de manière significative la fréquence des collectes majeures du GC.
    • Une nouvelle variable de réglage REMEMBERED_WB_UNPROTECTED_OBJECTS_LIMIT_RATIO a été introduite pour contrôler le nombre d'objets non protégés entraînant le déclenchement d'une collecte GC majeure. La valeur par défaut est de 0,01 (1 %). Cela permet de réduire considérablement la fréquence des collectes majeures de GC.
    • Des barrières d'écriture ont été implémentées pour de nombreux types de base qui en étaient dépourvus, notamment Time, Enumerator, MatchData, Method, File::Stat, BigDecimal et plusieurs autres. Cela permet de réduire considérablement le temps de collecte de la GC mineure et la fréquence de collecte de la GC majeure.
    • La plupart des classes principales utilisent désormais l'allocation à largeur variable, notamment Hash, Time, Thread::Backtrace, Thread::Backtrace::Location, File::Stat, Method. Ces classes sont ainsi plus rapides à allouer et à libérer, utilisent moins de mémoire et réduisent la fragmentation du tas.
    • La prise en charge des références faibles a été ajoutée au ramasse-miettes.


IRB

IRB a reçu plusieurs améliorations, y compris, mais sans s'y limiter :

  • Intégration avancée de irb:rdbg qui fournit une expérience de débogage équivalente à pry-byebug.
  • Prise en charge du pager pour les commandes ls, show_source et show_cmds.
  • Informations plus précises et plus utiles fournies par les commandes ls et show_source.
  • Autocomplétion expérimentale utilisant l'analyse de type.
  • Il est maintenant possible de changer la couleur et le style de la police dans la boîte de dialogue de complétion grâce à une classe nouvellement introduite Reline::Face


En outre, IRB a subi une refactorisation extensive et a reçu des dizaines de corrections de bogues afin de faciliter les améliorations futures.
Source : Ruby

Et vous ?

Quel est votre avis sur le sujet ?

Voir aussi :

Ruby 3.0.0 est disponible, cette version majeure est annoncée comme étant trois fois plus rapide que Ruby 2 et introduit plusieurs nouvelles fonctionnalités dont les Ractors, RBS et TypeProf

Pourquoi Ruby on Rails ne serait pas encore mort, d'après Patrick Helm, développeur back-end

La version 3.2 du langage de programmation Ruby est disponible. Elle apporte de nombreuses fonctionnalités et améliore les performances