1 Punkte von GN⁺ 2023-12-26 | 1 Kommentare | Auf WhatsApp teilen
  • YJIT verbessert Performance und Speicherverbrauch im Vergleich zu Ruby 3.2 deutlich und ist in Optcarrot mehr als 3-mal schneller als der Interpreter
  • Code GC von YJIT ist standardmäßig deaktiviert, und --yjit-exec-mem-size wirkt als Hard Limit, das die Kompilierung neuen Codes stoppt
  • Mit dem neu hinzugefügten RubyVM::YJIT.enable lässt sich YJIT zur Laufzeit aktivieren, ohne Kommandozeilenargumente oder Umgebungsvariablen zu ändern
  • Der Parser Prism wurde als Standard-gem hinzugefügt; die APIs Prism.parse(source), Prism.parse_comments(source) und Prism.parse_success?(source) sind verfügbar
  • Der Prism-Compiler kann mit ruby --parser=prism oder RUBYOPT="--parser=prism" experimentell ausprobiert werden, dieser Flag ist jedoch nur für Debugging gedacht
  • Der Parser-Generator wurde von Bison auf Lrama umgestellt, und der interne Parser von Lrama wurde zugunsten besserer Wartbarkeit durch einen von Racc erzeugten LR-Parser ersetzt
  • Der pure-Ruby-JIT-Compiler RJIT ersetzt MJIT, unterstützt jedoch nur die x86-64-Architektur unter Unix und ist auf experimentelle Zwecke beschränkt
  • Ein M:N thread scheduler wurde eingeführt, bei dem N native Threads M Ruby-Threads verwalten; da dies jedoch die Kompatibilität mit C-Erweiterungen beeinträchtigen kann, ist er im main Ractor standardmäßig deaktiviert
  • Die Nutzung von it, wenn es ohne Argumente aufgerufen und in Blöcken ohne normale Parameter verwendet wird, wird als deprecated markiert; in Ruby 3.4 soll es zur Referenz auf den ersten Blockparameter werden
  • Regexp::new erlaubt statt des seit Ruby 3.2 deprecated Aufrufs mit 3 Argumenten nur noch maximal 2 Argumente
  • ext/readline wurde eingestellt; künftig wird auf reline gesetzt, eine pure-Ruby-Implementierung, die mit der ext/readline-API kompatibel ist
  • Falls ext/readline benötigt wird, kann es über gem install readline-ext von rubygems.org installiert werden; Bibliotheken wie libreadline oder libedit müssen nicht mehr installiert sein
  • RubyGems und Bundler warnen, wenn bestimmte gems per require geladen werden, ohne sie dem Gemfile oder gemspec hinzuzufügen; diese gems werden in künftigen Ruby-Versionen zu bundled gems
  • Bei Nutzung des bootsnap-gems wird diese Warnung unterdrückt; aufgrund einer Einschränkung dieser Version wird empfohlen, die Anwendung mindestens einmal mit der Umgebungsvariable DISABLE_BOOTSNAP=1 auszuführen
  • prism 0.19.0 wurde als Standard-gem hinzugefügt, und racc 1.7.3 wurde von einem default gem zu einem bundled gem hochgestuft

1 Kommentare

 
GN⁺ 2023-12-26
Meinungen auf Hacker News
  • Mit Ruby 3.3 ist Ruby wirklich zurück, würde ich sagen. Es konzentriert sich auf die Freude der Entwickler, und eine Sprache, die früher als langsam verspottet wurde, ist jetzt nicht mehr langsam
    YJIT ist eine erstaunliche Technologie, und zusammen mit Object Shapes und verschiedenen Optimierungen der Garbage Collection wird Ruby ziemlich schnell. Selbst große Ruby-Anwender wie Shopify berichten von Leistungsverbesserungen im zweistelligen Prozentbereich, indem sie YJIT in der Vorabversion von 3.3 aktiviert und im Betrieb eingesetzt haben
    Persönlich freue ich mich sehr auf Ruby und seine Zukunft und würde gern mit Ruby 3.3 arbeiten und es auf Kundenseiten im Produktivbetrieb einsetzen
    https://railsatscale.com/2023-09-18-ruby-3-3-s-yjit-runs-sho...

    • Ich weiß nicht, ob ein kleiner Leistungsgewinn mich dazu bringen würde, Ruby neu zu wählen, aber schrittweise Verbesserungen sind willkommen. Sich übermäßig um Performance zu sorgen, ist fast immer verfrühte Optimierung, und Ruby war für alles, was ich bisher verlangt habe, schnell genug
      Ich habe es sogar für Glue Code zwischen einem Redis-basierten DNS-Record-Store und PowerDNS verwendet, und der gesamte Stack hat auf 14 kleinen VPSen 50 Milliarden Queries pro Monat verarbeitet, ohne in htop groß aufzufallen. Ich habe PowerDNS nicht wegen der Performance gewählt, sondern weil es in der Regel keine gute Idee ist, Dinge wie Kryptografie, HTTP oder DNS, die dem öffentlichen Internet ausgesetzt sind, selbst zu implementieren
      Die Ironie des heutigen Webs ist, dass Web-Apps aus „langsamem“ Ruby und Server-Side-Rendering in der Praxis Seiten oft schneller laden als wirklich langsame, final konsistente Datenbanken und aufgeblähte Frontend-Web-Apps. Im modernen Web sieht man selbst bei Kleinigkeiten viel zu oft Loading-Spinners
    • Die Ruby-Sprache selbst kann schnell sein, aber das gesamte Ökosystem ist quälend langsam. Wenn man mit Rails einen Server baut, der über Datenbankabfragen und Aufrufe anderer Services pro Request 1 MB JSON zurückgibt, kamen wir auf etwa 100 Requests pro Sekunde; nachdem wir denselben Service in Go neu geschrieben hatten, verarbeitete er 100.000 Requests pro Sekunde
    • Ich hatte mich gefragt, ob „Leistungsverbesserung im zweistelligen Bereich“ heißt, dass es 10 % schneller ist, oder 10-mal schneller
      Nach dem Klick auf den Link war klar: Es waren Verbesserungen im Bereich von 10 %. Das dürfte an der Wahrnehmung, dass Ruby gegenüber „schnellen“ Sprachen wie Rust, Java, Go oder C++ grob 50- bis 200-mal langsamer ist, nicht viel ändern
    • Ein Bereich, in dem Ruby die Developer Experience verbessern könnte, ist ein besseres Debugging-Erlebnis. Vielleicht bin ich zu sehr an Chrome DevTools gewöhnt, aber als ich zuletzt Ruby-Code mit viel Metaprogrammierung debuggt habe, war es schmerzhaft herauszufinden, was eigentlich passiert
    • Als ich „zweistellig“ hörte, hatte ich 50 % oder 80 % erwartet, aber im Link standen 13–15 %
  • Ruby 3.3 scheint eines der wichtigsten und funktionsreichsten Ruby-Releases der letzten zehn Jahre zu sein. Ich hätte nicht gedacht, dass es vor Python ein produktionsreifes JIT geben würde, und dazu kommen noch Prism, Lrama und IRB
    Was aber nicht genug besprochen wird, sind Ractor, der M:N-Thread-Scheduler, Fiber und Async. Mich würde besonders im Rails-Kontext interessieren, ob jemand diese Funktionen in Produktionsumgebungen einsetzt und welche Erfahrungen es dazu gibt

    • Dass Ruby vor Python ein produktionsreifes JIT veröffentlicht hat, war durchaus vorhersehbar. Ruby hatte eben keine riesige Scientific-Computing-Community, die von Implementierungsdetails des Host-Interpreters abhängt
    • Ich frage mich, ob Ruby 3.3 wirklich so ein bedeutendes Release ist. Ich bin mir nicht sicher, was genau daran so wichtig sein soll
      Trotzdem verdient Ractor mehr Aufmerksamkeit. Das ist ein enorm großes Feature
    • Ich verstehe wirklich nicht, warum es keine einheitliche Job Queue gibt, die sowohl Ruby als auch Python abdeckt. Irgendwann haben Leute angefangen, Informationen über HTTP-basierte Microservices auszutauschen, aber letztlich wäre eine einfache Job Queue mit einem gemeinsamen Speicherformat für beide Sprachen der bessere Weg, um Ruby/Rails-basierte Systeme mit dem Machine-Learning-Stack zu verbinden
      Vermutlich gibt es in Unternehmen intern Tausende private, maßgeschneiderte Lösungen auf Basis von RabbitMQ oder Redis
  • Jedes Jahr zu Weihnachten bringt Ruby Lang mit der Präzision eines Uhrwerks ein neues Release heraus

  • Auf Heroku verfügbar: https://devcenter.heroku.com/changelog-items/2772

  • Sieht gut aus. Das neue IRB ist ein interaktiver Ruby-Interpreter mit besserer Autovervollständigung und verbessertem Debugging. Die meisten Änderungen in Ruby 3.3 dürften auf Verbesserungen bei den Entwicklerwerkzeugen hinauslaufen
    Die Sprach-API bleibt insgesamt weitgehend konsistent mit früheren Releases. Ich habe einen Leitfaden zum Update auf Ruby 3.3 geschrieben, inklusive Hinweisen zu verschiedenen Versionsmanagern: https://mac.install.guide/ruby/update.html
    Ich bin neugierig, welchen Versionsmanager man empfehlen kann. Früher habe ich asdf, frum und chruby empfohlen

    • Mit rbenv oder asdf hatte ich keine nennenswerten Probleme. Ich nutze beide lokal und in Produktionsumgebungen
  • Namensauflösung wie bei Socket.getaddrinfo kann jetzt unterbrochen werden, und wann immer Namensauflösung nötig ist, wird dafür ein Worker-pthread erzeugt, in dem getaddrinfo(3) ausgeführt wird
    Ich frage mich, ob andere Sprachruntimes Ähnliches machen. Einen Thread zu erzeugen wirkt ziemlich schwergewichtig, aber vielleicht ist das in der Praxis kein großes Problem. Selbst laut den eigenen Benchmarks ist der Overhead klein, aber nicht null
    10000.times { Addrinfo.getaddrinfo("www.ruby-lang.org";, 80) } brauchte vor dem Patch 2,3 Sekunden und nach dem Patch 3,0 Sekunden, und 100.times { URI.open("https://www.ruby-lang.org";).read } brauchte vor dem Patch 3,36 Sekunden und nach dem Patch 3,40 Sekunden

    • Ich frage mich, ob das daran liegt, dass alle Ein-/Ausgabeoperationen der Standardbibliothek async/fiber unterstützen müssen
      Anders als in Python, wo dieselbe Operation noch einmal in einer async-„Farbe“ implementiert wird, hatte ich den Eindruck, dass hier alles grundsätzlich in Richtung Asynchronität verschoben wurde, bin mir aber nicht sicher, ob das stimmt
    • Ich hätte gedacht, dass Fiber leichtergewichtig ist als das Erzeugen eines neuen Threads
  • Ich frage mich, ob es sich lohnt, Ruby zu lernen, wenn man Python und NodeJS bereits kennt. Ruby wirkt interessant, fühlt sich aber schwierig an

    • Ruby ist im Grunde ein weniger populäres, dafür eleganteres Python. Es ist eine solide Allzwecksprache und eignet sich besonders gut für Aufgaben wie Shell-Skripting oder Datenbereinigung.
      Wenn man mit Node und Python vertraut ist, dürfte es ziemlich leicht zu lernen sein. Der Nachteil ist, dass es, wenn man diese Sprachen bereits kennt, grundsätzlich nichts völlig Neues ermöglicht. Der Vorteil ist vor allem ästhetisch: Ruby bietet und fördert Möglichkeiten, Code wirklich schön auszudrücken, und es macht Spaß, das zu erleben
    • Ich finde, Ruby ist für shell-artige Aufgaben und interaktives, exploratives Programmieren für Systemaufgaben viel besser als Python oder Node. Als „besseres bash“ oder „besseres Perl“ ist es schon wertvoll genug.
      Ich arbeite hauptsächlich in einer TypeScript-Codebasis, aber wenn ich mit Log-Daten oder halbstrukturiertem Text zu tun habe oder regex-basierte Umschreibungen über viele Dateien hinweg machen muss, greife ich oft zu Ruby. Ruby macht sehr viel Spaß und ist von den Sprachen, die ich regelmäßig verwendet habe, wahrscheinlich die unterhaltsamste — das ist schon für sich genommen eine Belohnung
    • Es hängt davon ab, was man sich davon erhofft. Der interessanteste Teil ist, dass Ruby Python in vieler Hinsicht sehr ähnlich und gleichzeitig doch ziemlich anders ist.
      Das größte Beispiel ist, dass Ruby Blöcke wirklich liebt. Sie sind überall in der Standardbibliothek, es gibt viel syntaktischen Zucker, und es gibt unzählige blockzentrierte DSLs. Auch typische funktionale Features sind schon lange in der Standardbibliothek enthalten, sodass man einen funktionalen Stil flüssig und gut lesbar schreiben kann.
      In Python ist das technisch meist auch möglich, aber es wirkt beim Schreiben und Lesen deutlich unbeholfener. Python hat Lambdas, scheint sie aber über triviale Verwendungen hinaus nicht besonders zu mögen; stattdessen werden Funktionen überall als First-Class-Values verwendet
    • Wenn man beim Lernen Hinweise bekommen möchte, wie man seinen Code verbessern kann, sollte man Rubocop verwenden. Es ist ein großartiger Linter und Lehrer
    • Vor etwas mehr als zehn Jahren, 2011–2013, habe ich ein wenig Ruby benutzt, genauer gesagt Ruby im Rahmen von Rails. Damals war noch das Nachglühen von RoR zu spüren, das 2005 aufkam und 2007–2009 riesig war.
      Leute mit Gespür für aktuelle Technologien wechselten zu API-orientierter Entwicklung auf Basis von node.js und AngularJS, die deutlich schneller war als Dinge, die mit RoR gebaut wurden. RoR wirkte 2013 bereits alt, weil der Standardansatz weiterhin monolithisch war und der Umstieg auf das neue Paradigma der Frontend-/Backend-Trennung nicht gut gelang.
      Der Grund, warum ich lang über ein Framework in Ruby und nicht über Ruby selbst gesprochen habe, ist, dass wohl auch heute noch 95 % der Ruby-Entwicklung Rails-Anwendungen sein dürften. Berühmt wurde Ruby größtenteils dank Ruby on Rails, und wenn RoR auf dem Rückzug ist, wird Ruby wohl demselben Verlauf folgen, bis nur noch eine kleine, leidenschaftliche Community wie bei Perl übrig bleibt.
      Wenn man nur die Sprache selbst betrachtet, fällt mir kein Grund ein, Ruby statt Python oder TypeScript zu wählen. Weder als Sprache noch als Plattform scheint Ruby etwas besser zu können als die bereits etablierteren Konkurrenten
  • Prism ist interessant. Ich frage mich, ob es Tools zur Analyse von Ruby-Code gibt, die es verwenden. Ich hatte nach einer Methode gesucht, den Code im Unternehmen zu analysieren

    • Ruby LSP verwendet Prism. Kevin Newton hat ein Prism-basiertes Backend für das whitequark/parser-Gem implementiert, das zusammen mit Rubocop verwendet werden kann: https://github.com/kddnewton/parser-prism
  • Die Umgebungsvariable RUBY_MAX_CPU=n setzt offenbar maximal N, also die maximale Zahl nativer Threads, und der Standardwert ist 8
    Ich hätte erwartet, dass der Standardwert wie bei Rusts Tokio oder vielen M:N-Laufzeiten die Anzahl logischer Kerne ist

    • Das ist eine Optimierung, die man später noch hinzufügen kann, und es gibt dabei einige Feinheiten. Soweit ich mich erinnere, war es bei Go einige Jahre lang ähnlich, und man setzte GO_MAX_PROCS in init() oder main()
    • Es wirkt nicht richtig, eine harte Obergrenze für die maximale CPU-Zahl zu setzen. Müsste es nicht genügen, von der Zahl der verfügbaren Kerne abzuhängen?
  • Ich hoffe, dass Ruby 4.0 explizite Imports erlaubt statt der heutigen impliziten Methode, Gems in den globalen Namespace zu laden

    • Chris Salzbergs Im könnte interessant sein. Es ist bereits in Ruby 3.2 nutzbar: https://github.com/shioyama/im
      Es gibt auch eine Diskussion über ein noch spekulatives Feature „namespace on read“: https://bugs.ruby-lang.org/issues/19744
    • Ob implizit oder explizit, ich halte den globalen Namespace für in Ordnung. Theoretisch wirkt er ungeschickt, in der Praxis verursacht er dank Konventionen und sozialer Normen aber nur selten Probleme.
      Dass der globale Namespace genau eine Version jedes Gems unterstützt, fördert zudem eine gesunde Kultur, die stabile ABIs und Schonfristen bei Abkündigungen wertschätzt. Im Vergleich zu manchen Sprachökosystemen ist das traumhaft
    • Ich glaube, das ist eher eine Rails- als eine Ruby-Sache. Ich weiß, dass der Unterschied in den meisten Projekten praktisch keine Rolle spielt, aber das könnte eine Entscheidung des Rails-Teams sein und nichts mit der Arbeit des Ruby-Teams zu tun haben.
      Oder ich liege komplett daneben
    • Ruby 4.0 werden wir wohl vor 2030 kaum sehen
      https://youtu.be/4MM5b2F9zrM?si=UT3aUbD6p_uBZehS&t=2347