Skip to content
← Wszystkie wpisy
5 min czytania Dawid Skłodowski

Ruby 3.3: YJIT przyspiesza, a Prism przepisuje parser

Nagłówkiem Ruby 3.3 jest szybszy, dojrzalszy YJIT — ale cichszą, bardziej brzemienną zmianą jest Prism, nowy parser tolerujący błędy, który staje się standardem. Spojrzenie na to, co jest w tegorocznym świątecznym wydaniu, co dostajesz za darmo i dlaczego nowy parser ma większe znaczenie, niż brzmi.

Są święta, co zgodnie z długą tradycją oznacza nowe Ruby. Ruby 3.3 przybyło dziś, a jego dwie najistotniejsze zmiany ciągną w różnych kierunkach: jedna to historia wydajności, którą już słyszałeś, ale która wciąż się poprawia — YJIT — a druga to kawałek fundamentalnej hydrauliki, której większość deweloperów nigdy nie dotknie bezpośrednio, ale która po cichu poprawia cały ekosystem — Prism, nowy parser. Żadna nie zmienia tego, jak piszesz Ruby. Obie zmieniają to, co dostajesz za jego uruchamianie. Omówmy, co jest w wydaniu i dlaczego nieefektowna zmiana parsera może mieć, w dłuższej perspektywie, większe znaczenie niż nagłówkowa szybkość.

YJIT: historia wydajności wciąż się kumuluje

YJIT — kompilator just-in-time Ruby, który kompiluje gorący kod Ruby do kodu maszynowego w czasie wykonania — był przewodnią nicią ostatnich wydań Ruby, i 3.3 ją kontynuuje. Ta wersja czyni YJIT szybszym i, co ważne, bardziej oszczędnym pamięciowo niż wcześniej, i jest teraz dość dojrzały, by być naprawdę bezpiecznym domyślnym dla obciążeń produkcyjnych, a nie eksperymentalną flagą.

Rzeczą, którą cenię w historii YJIT, jest jej uczciwość co do tego, co JIT robi, a czego nie robi. Przyspiesza Ruby związany z CPU — kod, który spędza czas wykonując instrukcje Ruby: obliczenia, manipulację obiektami, własną pracę interpretera. Dla typowej aplikacji Railsów, gdzie żądanie spędza dużo czasu czekając na bazę i inne I/O, YJIT pomaga plasterkowi wykonania-Ruby żądania, nie czekaniu. Więc zysk w realnym świecie waha się mocno wedle obciążenia: aplikacja robiąca ciężkie obliczenia w-Ruby widzi znaczny skok, podczas gdy ta, która głównie czeka na Postgres, widzi mniejszą (ale wciąż realną i darmową) poprawę. To nie zarzut — to dokładnie właściwy sposób, by rozumieć funkcję wydajności. To nie magiczny przełącznik „wszystko szybsze”; czyni wykonanie Ruby szybszym, a jak bardzo to pomaga, zależy od tego, ile twojego czasu jest spędzane na wykonywaniu Ruby kontra czekaniu na I/O.

Praktyczny wniosek jest prosty i przyjemny: włącz YJIT, zmierz własną aplikację i weź darmową szybkość. Dojrzałość w 3.3 oznacza, że jest mało powodów, by tego nie robić. Tylko trzymaj właściwy model mentalny co przyspieszyło, byś mógł przewidzieć, czy twoje konkretne obciążenie zobaczy dużo czy mało — i byś nie był zaskoczony, gdy aplikacja związana z I/O zyskuje mniej, niż sugerują nagłówki benchmarków.

Prism: nowy parser pod podłogą

Cichszą i, twierdziłbym, bardziej fundamentalną zmianą jest Prism, nowy parser dla Ruby, który wysyła się w 3.3 i ma stać się standardowym sposobem parsowania źródła Ruby. Parser to rzecz, która czyta twój kod źródłowy Ruby i zamienia go w strukturyzowaną formę, z którą pracuje interpreter (i twoje narzędzia). To mniej więcej tak głęboko w hydraulice, jak sięga oprogramowanie — przeciętny deweloper nigdy o tym nie myśli — co jest dokładnie tym, dlaczego dobry nowy jest po cichu ważny.

Co czyni Prism ważnym:

  • Toleruje błędy. Tradycyjne parsery mają tendencję poddawać się przy pierwszym błędzie składni. Prism jest zaprojektowany, by odzyskiwać i iść dalej, produkując użyteczny wynik nawet z kodu, który nie w pełni się parsuje. Brzmi to akademicko, dopóki nie przypomnisz sobie, co używa parsera: twój edytor, twój serwer języka, twój linter, twój formatter. Tolerancja błędów oznacza, że edytor wciąż może rozumieć i pomagać z twoim plikiem gdy jesteś w środku pisania i jest tymczasowo nieprawidłowy — co jest przez większość czasu, gdy faktycznie piszesz kod. Lepsze narzędzia dla wszystkich, w dół od jednej zmiany parsera.
  • To dzielona, przenośna biblioteka. Prism jest zbudowany, by być używanym przez wszystkie implementacje Ruby i narzędzia, nie tylko CRuby — pojedynczy, dobrze utrzymywany parser, na którym cały ekosystem może budować, zamiast każdego narzędzia reimplementującego parsowanie Ruby nieco inaczej i nieco błędnie. Ten rodzaj konsolidacji czyni każde narzędzie w dół bardziej poprawnym i spójnym.

Niemal na pewno nigdy nie zawołasz Prism bezpośrednio. Jego wartość płynie całkowicie przez narzędzia zbudowane na nim — edytory rozumiejące w-połowie-wpisany kod, lintery i formattery zgadzające się co do tego, co twój kod znaczy, serwery języka dające lepsze uzupełnienia. To infrastruktura, a dobra infrastruktura jest niewidzialna. Ale przez kolejne kilka lat sporo narzędzi Ruby, których używasz codziennie, stanie się lepszych z powodu tego parsera, bez robienia przez ciebie czegokolwiek. To większa sprawa, niż brzmi w dniu wydania.

Dlaczego nudna zmiana to ta większa

Jest tu wzorzec wart nazwania, i echo punktu z Rails 7.1 z zeszłego kwartału: funkcja z nagłówka (szybkość YJIT) to ta, która dostaje uwagę, ale zmiana infrastruktury (parser) to często ta o dłuższym zasięgu. Przyspieszenie YJIT jest realne, mile widziane i powinieneś je wziąć — ale to przyrostowe usprawnienie historii, którą już znałeś. Prism to nowy fundament, na którym cały ekosystem narzędzi będzie budował latami, kumulując się po cichu w lepsze edytory i narzędzia w całej społeczności. Efektowna liczba rusza się dziś; nudna hydraulika opłaca się powoli i dla wszystkich. Oba rodzaje zmiany mają znaczenie, ale warto wytrenować się, by zauważać ten fundamentalny, bo to ten, który komunikat prasowy niedocenia.

Reszta wydania

Jak zawsze, świąteczne wydanie niesie więcej niż swoje dwa nagłówki. Ruby 3.3 kontynuuje pracę nad współbieżnością (scheduler wątków M:N wprowadzony, by lepiej wykorzystać wątki, wciąż dojrzewa) i wnosi zwykły strumień udoskonaleń biblioteki standardowej, poprawek wydajności i małego poleru języka. Nic z tego nie wymaga przepisania. To charakterystyczne dla dojrzałych wydań Ruby — i dojrzałych platform ogólnie: wielkie zamachy są za nami, a postęp wygląda teraz jak stałe, kumulujące się udoskonalenie, a nie wstrząs. Po dość latach „nic, czego musisz się uczyć od nowa, kilka rzeczy, które po cichu stały się lepsze” to dokładnie to, czego chcesz od wydania języka.

Werdykt

Ruby 3.3 to charakterystyczne świąteczne wydanie: nic, co zmienia, jak piszesz Ruby, dwie rzeczy, które zmieniają, co dostajesz za jego uruchamianie. YJIT jest szybszy i bardziej oszczędny pamięciowo i teraz dość dojrzały, by być bezpiecznym domyślnym produkcyjnym — włącz go, zmierz i weź darmową szybkość, trzymając uczciwy model mentalny, że przyspiesza wykonanie Ruby związane z CPU, nie I/O, na które twoja aplikacja spędza dużo czasu czekając, więc zysk zależy od obciążenia. Prism, nowy parser tolerujący błędy, to cichsza zmiana i prawdopodobnie bardziej brzemienna: nigdy nie zawołasz go bezpośrednio, ale edytory, lintery, formattery i serwery języka zbudowane na nim będą lepsze latami, bo dzielony, zdolny do odzyskiwania parser to dokładnie rodzaj fundamentu, którego potrzebują dobre narzędzia. Weź szybkość YJIT dziś; doceń, że Prism to zmiana, która się kumuluje. To znak dojrzałej platformy, że jej najlepsze wydanie w danym roku nie prosi cię o nic i po cichu poprawia wszystko — i to dokładnie to, co robi 3.3.