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

Ruby 2.6: podgląd JIT i nieskończone zakresy

Ruby 2.6.0 ukazuje się w Boże Narodzenie z pierwszym krokiem ku kompilatorowi JIT — dużą sprawą dla przyszłości Ruby — plus nieskończone zakresy, then jako alias dla yield_self i Bundler w bibliotece standardowej. Praktyczny przegląd.

Ruby 2.6.0 przybyło w Boże Narodzenie, a choć codzienne dodatki są przyjemne jak zwykle, nagłówek jest strategicznie znaczący: Ruby dostaje swój pierwszy kompilator JIT, jako eksperymentalny podgląd. To jeszcze nie powód do aktualizacji sam w sobie, ale pierwszy widoczny krok wieloletniego wysiłku, by uczynić Ruby znacząco szybszym — fundament słynnego celu „Ruby 3x3”. Oto przegląd, z nagłówkiem o tym, co to znaczy dla przyszłości języka.

MJIT: pierwszy krok ku szybszemu Ruby

Wielką wiadomością jest MJIT, pierwszy kompilator just-in-time Ruby, przybywający jako eksperymentalny, opt-in podgląd. JIT kompiluje często uruchamiany kod do natywnego kodu maszyny w czasie działania i jest centralną techniką stojącą za uczynieniem języków interpretowanych szybkimi. Podejście Ruby jest nietypowe i pragmatyczne: MJIT zapisuje kod C na dysk i używa systemowego kompilatora C, by skompilować gorące metody w biblioteki współdzielone, które VM potem ładuje.

ruby --jit my_program.rb        # zgłoś się do JIT

Uczciwa ocena dla 2.6: MJIT nie jest jeszcze wygraną dla typowych aplikacji Rails. Obecnie pomaga obciążeniom związanym z CPU, ciężkim obliczeniowo, podczas gdy aplikacje Rails — zdominowane przez I/O, dyspozycję metod i alokację pamięci, a nie ciasne pętle numeryczne — widzą małą korzyść, a czasem regresję. Więc nie włączasz go na produkcji dziś. Jego znaczenie jest jako początek: to widoczny start ambicji „Ruby 3x3” (Ruby 3 będący trzy razy szybszy niż Ruby 2), a przez następnych kilka wydań to tu zostanie napisana historia wydajności Ruby. Warte bacznego obserwowania, nie wdrażania jeszcze.

Nieskończone zakresy

Mały, naprawdę przydatny dodatek składniowy: zakresy bez górnej granicy, (n..). Czytają się naturalnie i porządkują częste wzorce:

# "wszystko od indeksu 2 w górę"
items[2..]                       # było items[2..-1]

# warunek bez końca w case
case score
when 90.. then "A"
when 70.. then "B"
else           "C"
end

# scope'y / porównania czytane „n lub więcej”
ages.select { |a| (18..).cover?(a) }

array[2..] w znaczeniu „od indeksu 2 do końca” jest jaśniejsze niż lekko zagadkowe array[2..-1], którego wszyscy się nauczyli, a nieskończone zakresy błyszczą w case/when dla „ten próg lub powyżej”. Drobna funkcja, którą przyjmiesz bez zastanawiania się.

then: czytelna nazwa dla yield_self

Ruby 2.5 wprowadziło yield_self — metodę przypominającą pipe, która podaje odbiorcę do bloku — ale jej nazwa była toporna. 2.6 dodaje then jako alias, i czyta się znacznie lepiej:

# ten sam potok wartości, teraz czytelny
config
  .then { |c| build_url(c) }
  .then { |u| fetch(u) }
  .then { |r| parse(r) }

Ta sama zdolność, znacznie ładniejsza nazwa. then czyni potok „weź tę wartość, potem zrób to, potem to” czytanym jak po angielsku, i to forma, po którą będziesz sięgać zamiast yield_self od teraz.

Dodatki do kolekcji i Enumerable

Użyteczna porcja metod do pracy z kolekcjami:

  • Array#union, #difference, #intersection dają nazwane, czytelne alternatywy dla symbolicznych operatorów zbiorów (|, -, &) i, w przeciwieństwie do operatorów, przyjmują wiele argumentów: a.union(b, c).
  • Enumerable#chain leniwie konkatenuje enumerable w jeden bez budowania pośredniej tablicy — (1..3).chain([4, 5]).each { ... } — przydatne do iterowania kilku kolekcji jako jednej.
  • Enumerable#filter przybywa jako alias dla select, dopasowując nazewnictwo Ruby do terminu, którego używa większość innych języków.

Żaden nie jest głęboki, ale każdy zastępuje mały idiom jaśniejszą metodą.

Bundler w bibliotece standardowej

Po cichu znacząca zmiana dla ekosystemu: Bundler jest teraz dołączony do Ruby jako część biblioteki standardowej. Bundler był uniwersalnym menedżerem zależności od lat, ale był osobnym gemem, który instalowałeś; uczynienie go częścią samego Ruby uznaje tę rzeczywistość i wygładza konfigurację — świeża instalacja Ruby przychodzi teraz z narzędziami zależności, których używa każdy projekt, bez dodatkowego kroku. Małe, ale usuwa drzazgę z onboardingu i CI.

Mniejsze dodatki

Dopełniając wydanie: Kernel#then jak omówiono; Proc#call i przekazywanie bloków robią się szybsze (kontynuując stałą pracę nad wydajnością); przypisanie stałej można uczynić podnoszącym błąd przy redefinicji, pomagając łapać przypadkowe nadpisanie stałych; i zwykła runda udoskonaleń biblioteki standardowej oraz deprecjacji. Niedramatyczne porządki trwają.

Czy aktualizować?

Tak dla funkcji języka, bez pośpiechu dla JIT. Codzienne dodatki — nieskończone zakresy, then, metody kolekcji, Bundler w stdlib — są przyjemne, addytywne i bez ryzyka, więc przyjmujesz je naturalnie. JIT to ten nie do wdrażania jeszcze: to eksperymentalny podgląd, który nie pomaga (a może szkodzić) typowym obciążeniom Rails w 2.6, więc zostaw go wyłączonym na produkcji na razie. Ale zrozum jego znaczenie — to otwierające posunięcie wieloletniego pchnięcia Ruby ku byciu dramatycznie szybszym, cel „3x3” uczyniony widocznym. Aktualizuj dla ergonomii dziś i obserwuj, jak JIT dojrzewa przez następne wydania, bo to tam za chwilę rozwinie się ciekawa historia wydajności. Charakterystycznie praktyczne wydanie gwiazdkowe, z strategicznie ważnym ziarnem zasianym w środku.