Ruby 3.1: YJIT ląduje i nowy debugger
Ruby 3.1 przybywa w Boże Narodzenie z YJIT — nowym JIT od Shopify, który wreszcie przyspiesza realne obciążenia Rails, nie tylko benchmarki — plus nowoczesny debugger, lepsze komunikaty błędów i wygodną składnię. Praktyczny przegląd.
Ruby 3.1.0 przybyło w Boże Narodzenie, a nagłówkiem jest ten, na który czekałem, odkąd JIT pierwszy raz się pojawił w 2.6: JIT, który faktycznie pomaga Railsom. Wcześniejszy MJIT był prawdziwą inżynierią, ale, jak odnotowałem wtedy, mało robił dla typowych obciążeń webowych zdominowanych przez I/O i dyspozycję metod. YJIT, wniesiony przez Shopify i dostarczany w 3.1, to zmienia. Obok niego przybywa naprawdę dobry debugger, znacznie lepsze komunikaty błędów i miła składnia. Oto przegląd.
YJIT: JIT, który pomaga prawdziwym aplikacjom
Wielką wiadomością jest YJIT (Yet Another Ruby JIT), nowy kompilator just-in-time od Shopify zbudowany inną techniką (lazy basic-block versioning) niż stary MJIT. Kluczową różnicą jest ta, która ma znaczenie w praktyce: tam, gdzie MJIT pomagał głównie benchmarkom związanym z CPU, YJIT dostarcza realne przyspieszenia na faktycznych obciążeniach Rails — mocno dyspozycjonującym metody, mocno alokującym kodzie, który produkcyjne aplikacje webowe faktycznie uruchamiają. Shopify zbudowało go właśnie dlatego, że potrzebowali, by ich ogromny monolit Rails działał szybciej, i działa, na produkcji, na realnym ruchu.
ruby --yjit my_app.rb # zgłoś się do YJIT
# albo RUBY_YJIT_ENABLE=1 / konfiguracja w aplikacji
To historia JIT wreszcie opłacająca się ludziom czytającym te wpisy. Zastrzeżenie z 2.6 — „JIT jeszcze nie pomaga Railsom, obserwuj to miejsce” — jest rozwiązane: YJIT to coś, co możesz faktycznie włączyć dla aplikacji Rails i zmierzyć znaczącą poprawę (raportowane dwucyfrowe procentowe przyspieszenia na realnych obciążeniach), z większą ilością w drodze, gdy dojrzeje. Wciąż jest młody w 3.1 i szybko się poprawia, ale to moment, w którym wieloletnie pchnięcie wydajności Ruby dociera do aplikacji webowych, które większość z nas buduje.
Nowoczesny debugger: debug.gem
Drugim wyróżnikiem jest nowy gem debug, teraz dołączony i rekomendowany debugger. Latami
debugowanie Ruby oznaczało byebug, pry albo rozsypywanie puts; nowy debug to nowoczesny
debugger od podstaw, który jest szybki, pełnofunkcyjny i integruje się z edytorami (zwłaszcza UI
debugowania VS Code) oraz zdalnym debugowaniem:
require "debug"
def calculate(order)
debugger # wpada tu w potężną, szybką sesję debuggera
# step, next, breakpointy, watchpointy, zdalne podłączenie…
end
Wspiera rzeczy, które poważny debugger powinien — breakpointy (w tym warunkowe i watchpointy), krokowanie, inspekcję ramek i podłączanie do działającego procesu zdalnie — i jest zauważalnie szybszy niż starsze narzędzia. Posiadanie dobrego, oficjalnego debuggera w bibliotece standardowej (ta sama trajektoria co odświeżenie irb) to realna poprawa jakości życia i warta przejścia z byebug/pry.
error_highlight: błędy wskazujące miejsce
Mały, lecz zachwycający dodatek: error_highlight sprawia, że komunikaty błędów wskazują
dokładną część linii, która spowodowała problem, nie tylko linię:
NoMethodError: undefined method `name' for nil
user.profile.name
^^^^^^^^
Gdy user.profile jest nil, błąd podkreśla profile.name, więc widzisz natychmiast, która część
łańcuchowego wyrażenia była nil — zamiast gapić się na długą linię, zastanawiając się, która .
wybuchła. Na ruchliwej linii z kilkoma wywołaniami metod to zamienia moment mrużenia oczu w
natychmiastową diagnozę. Jest włączone domyślnie i to rodzaj drobiazgu, który po cichu oszczędza czas
debugowania codziennie.
Przyjemności składniowe
Kilka dodatków składniowych poprawiających jakość życia:
-
Pominięcie wartości literału hasha. Gdy klucz hasha pasuje do nazwy zmiennej lokalnej, możesz pominąć wartość —
{ x:, y: }znaczy{ x: x, y: y }:name = "Ada"; age = 36 person = { name:, age: } # => { name: "Ada", age: 36 }To drobiazg usuwający częsty kawałek powtórzenia, zwłaszcza przy budowaniu hashy ze zmiennych, które właśnie obliczyłeś.
-
Pinowanie wyrażeniami w pattern matchingu. Operator pin przyjmuje teraz wyrażenia:
in { count: ^(a + b) }, czyniąc pattern matching (teraz ustaloną funkcję) bardziej elastycznym. -
Usprawnienia IRB trwają — autouzupełnianie i wyświetlanie dokumentacji czynią konsolę jeszcze milszą, budując na odświeżeniu z 2.7.
Czy aktualizować?
Tak — i to wydanie z naprawdę ekscytującym powodem ponad zwykłe. YJIT to długo wyczekiwany JIT, który
pomaga prawdziwym aplikacjom Rails; możesz go włączyć i zmierzyć realną poprawę, a będzie tylko
lepszy. Nowy gem debug jest wart przyjęcia ponad twój stary debugger za szybkość i integrację z
edytorem. error_highlight i przyjemności składniowe to darmowa, addytywna jakość życia. A ponieważ
duża zmiana łamiąca (argumenty nazwane) była w 3.0, skok z 3.0 do 3.1 jest gładki.
Łuk od podglądu JIT z 2.6 do tu jest satysfakcjonujący do prześledzenia: podróż wydajności „3×3” dała Ruby szybszy runtime, ale JIT konkretnie nie pomagał aplikacjom webowym aż do teraz — a 3.1 to miejsce, gdzie to wreszcie ląduje, dzięki firmie, która uruchamia jedną z największych aplikacji Rails na świecie potrzebując tego. Silne wydanie i stosowne, by zamknąć rok.