1 poin oleh GN⁺ 2023-12-26 | 1 komentar | Bagikan ke WhatsApp

Ruby 3.3.0 dirilis

  • Versi Ruby 3.3.0 telah dirilis. Pembaruan ini menghadirkan parser baru Prism, penggunaan Lrama sebagai generator parser, penambahan kompiler JIT RJIT yang ditulis dengan Ruby murni, dan terutama peningkatan performa pada YJIT.

Parser Prism

  • Prism adalah parser recursive descent yang portabel, tangguh terhadap error, dan mudah dipelihara untuk bahasa Ruby, serta disediakan sebagai gem bawaan.
  • Prism layak digunakan di lingkungan produksi, dipelihara secara aktif, dan dapat digunakan sebagai pengganti Ripper.
  • Tersedia dokumentasi rinci tentang cara menggunakan Prism.
  • Prism adalah library C yang digunakan di dalam CRuby sekaligus gem Ruby yang dapat dipakai oleh semua alat yang perlu mem-parsing kode Ruby.
  • Metode utama pada API Prism antara lain Prism.parse(source), Prism.parse_comments(source), Prism.parse_success?(source).
  • Kontribusi dapat dilakukan dengan langsung mengirim pull request atau issue ke repositori Prism.
  • Untuk mencoba kompiler Prism secara eksperimental, можно menggunakan ruby --parser=prism atau RUBYOPT="--parser=prism", tetapi sebaiknya hanya untuk tujuan debugging.

Generator parser Lrama

  • Bison digantikan oleh generator parser LALR Lrama.
  • Siapa pun yang tertarik dapat melihat visi masa depan parser Ruby.
  • Untuk kemudahan pemeliharaan, parser internal Lrama diganti dengan parser LR yang dihasilkan oleh Racc.
  • Mendukung aturan berparameter (?, *, +), dan akan digunakan di Ruby parse.y.

YJIT

  • Ada peningkatan performa besar dibanding Ruby 3.2.
  • Dukungan untuk argumen splat dan rest ditingkatkan.
  • Register kini dialokasikan untuk operasi stack pada virtual machine.
  • Lebih banyak pemanggilan dengan argumen opsional dapat dikompilasi. Exception handler juga dapat dikompilasi.
  • Tipe pemanggilan yang sebelumnya tidak didukung dan call site megamorfik tidak lagi keluar ke interpreter.
  • Metode bawaan seperti #blank? milik Rails dan #present? versi khusus kini di-inline.
  • Integer#*, Integer#!=, String#!=, String#getbyte, Kernel#block_given?, Kernel#is_a?, Kernel#instance_of?, Module#=== dan lainnya dioptimalkan secara khusus.
  • Kecepatan kompilasi sedikit lebih cepat daripada Ruby 3.2.
  • Pada Optcarrot, performanya lebih dari 3x lebih cepat dibanding interpreter.
  • Penggunaan memori meningkat secara signifikan dibanding Ruby 3.2.
  • Metadata untuk kode yang sudah dikompilasi menggunakan memori jauh lebih sedikit.
  • --yjit-call-threshold dinaikkan dari 30 menjadi 120 secara otomatis untuk aplikasi dengan lebih dari 40.000 ISEQ.
  • --yjit-cold-threshold ditambahkan untuk melewati kompilasi ISEQ yang sudah dingin.
  • Di Arm64, kode yang dihasilkan lebih ringkas.
  • Code GC dinonaktifkan secara default.
  • --yjit-exec-mem-size diperlakukan sebagai hard limit saat kompilasi kode baru dihentikan.
  • Tidak ada penurunan performa akibat code GC, dan saat server melakukan refork menggunakan Pitchfork, perilaku copy-on-write menjadi lebih baik.
  • Jika diinginkan, code GC dapat diaktifkan dengan --yjit-code-gc.
  • RubyVM::YJIT.enable ditambahkan agar YJIT dapat diaktifkan saat runtime.
  • Rails 7.2 berencana menggunakan cara ini untuk mengaktifkan YJIT secara default.
  • Metode ini dapat dipakai jika ingin mengaktifkan YJIT hanya setelah aplikasi selesai booting.
  • Jika ingin menonaktifkan YJIT saat boot namun tetap memakai opsi YJIT lain, gunakan --yjit-disable.
  • Secara default kini tersedia lebih banyak statistik YJIT.
  • yjit_alloc_size dan berbagai statistik terkait metadata tersedia secara default.
  • Statistik ratio_in_yjit yang dihasilkan oleh --yjit-stats kini tersedia pada release build. Tidak lagi memerlukan build statistik khusus atau build pengembangan.
  • Lebih banyak kemampuan profiling telah ditambahkan.
  • --yjit-perf ditambahkan untuk memudahkan profiling bersama Linux perf.
  • --yjit-trace-exits mendukung sampling dengan --yjit-trace-exits-sample-rate=N.
  • Pengujian yang lebih menyeluruh dan banyak perbaikan bug juga dilakukan.

RJIT

  • Kompiler JIT RJIT yang ditulis dengan Ruby murni diperkenalkan dan menggantikan MJIT.
  • RJIT hanya didukung pada arsitektur x86-64 di platform Unix.
  • Berbeda dengan MJIT, RJIT tidak memerlukan kompiler C saat runtime.
  • RJIT hanya tersedia untuk tujuan eksperimental.
  • Untuk lingkungan produksi, YJIT tetap yang sebaiknya digunakan.
  • Jika tertarik pada pengembangan Ruby JIT, disarankan melihat presentasi k0kubun pada hari ke-3 RubyKaigi.

Scheduler thread M:N

  • Scheduler thread M:N diperkenalkan.
  • Karena M thread Ruby dikelola oleh N thread native (thread sistem operasi), biaya pembuatan dan pengelolaan thread berkurang.
  • Scheduler thread M:N dinonaktifkan secara default pada Ractor utama karena dapat merusak kompatibilitas dengan ekstensi C.
  • Thread M:N dapat diaktifkan pada Ractor utama dengan variabel lingkungan RUBY_MN_THREADS=1.
  • Pada Ractor non-utama, thread M:N selalu aktif.
  • Variabel lingkungan RUBY_MAX_CPU=n menetapkan jumlah maksimum N (jumlah maksimum thread native). Nilai defaultnya 8.
  • Karena hanya satu thread Ruby yang dapat berjalan per Ractor, aplikasi single Ractor (sebagian besar aplikasi) hanya menggunakan 1 thread native.
  • Lebih banyak thread native daripada N dapat digunakan untuk mendukung pekerjaan yang blocking.

Peningkatan performa

  • defined?(@ivar) dioptimalkan menggunakan Object Shapes.
  • Resolusi nama seperti Socket.getaddrinfo kini bisa diinterupsi (pada lingkungan yang mendukung pthreads).
  • Ada berbagai peningkatan performa pada garbage collector.
    • Ketika objek muda direferensikan oleh objek tua, objek tersebut tidak langsung dipromosikan ke generasi tua sehingga frekuensi major GC berkurang drastis.
    • Variabel tuning baru REMEMBERED_WB_UNPROTECTED_OBJECTS_LIMIT_RATIO diperkenalkan untuk mengontrol jumlah objek tak terlindungi yang memicu major GC. Nilai defaultnya 0,01 (1%), sehingga frekuensi major GC berkurang signifikan.
    • Write Barrier diterapkan pada banyak tipe inti yang sebelumnya belum memilikinya. Ini sangat mengurangi waktu minor GC dan frekuensi major GC.
    • Sebagian besar kelas inti kini menggunakan Variable Width Allocation. Dampaknya, alokasi dan dealokasi pada kelas-kelas ini menjadi lebih cepat, penggunaan memori berkurang, dan fragmentasi heap menurun.
    • Dukungan weak reference ditambahkan ke garbage collector.

Perubahan penting lainnya

  • IRB menerima berbagai peningkatan, termasuk integrasi lanjutan irb:rdbg, dukungan pager untuk perintah ls, show_source, dan show_cmds, peningkatan akurasi dan kegunaan informasi dari perintah ls dan show_source, serta auto-complete eksperimental berbasis analisis tipe.
  • IRB juga mengalami refactoring besar-besaran untuk memudahkan peningkatan ke depan dan menerima puluhan perbaikan bug.

Masalah kompatibilitas

  • Pemanggilan it di dalam blok tanpa argumen tidak lagi direkomendasikan, dan pada Ruby 3.4 akan merujuk ke parameter blok pertama.
  • Variabel lingkungan yang sudah tidak digunakan dihapus.

Pembaruan standard library

  • RubyGems dan Bundler akan menampilkan peringatan jika pengguna me-require gem berikut tanpa menambahkannya ke Gemfile atau gemspec. Ini karena gem-gem tersebut akan menjadi bundled gem pada versi Ruby mendatang.
  • Gem bawaan berikut ditambahkan atau diperbarui: prism 0.19.0, RubyGems 3.5.3, abbrev 0.1.2, dan banyak lainnya.
  • Bundled gem berikut dipromosikan dari default gem atau diperbarui: racc 1.7.3, minitest 5.20.0, dan banyak lainnya.

Opini GN⁺

  • Pengenalan parser Prism: Salah satu fitur terpenting Ruby 3.3.0 adalah hadirnya parser baru Prism. Ini akan sangat membantu pengembang Ruby dengan menyediakan parser yang lebih efisien untuk mem-parsing kode Ruby, lebih tahan terhadap error, dan lebih mudah dipelihara.
  • Peningkatan performa YJIT: Peningkatan performa besar pada YJIT akan sangat meningkatkan kecepatan eksekusi aplikasi Ruby, dan khususnya pengurangan penggunaan memori serta optimasi GC akan memberi dampak positif pada performa dan stabilitas aplikasi Ruby berskala besar.
  • Scheduler thread M:N: Pengenalan scheduler thread M:N memiliki potensi untuk meningkatkan performa aplikasi Ruby multithread. Ini akan mengurangi biaya pengelolaan thread dan memungkinkan pemrosesan paralel yang lebih efisien.

1 komentar

 
GN⁺ 2023-12-26
Opini Hacker News
  • Dengan hadirnya Ruby 3.3, Ruby—bahasa yang mengutamakan kebahagiaan developer—berhasil meninggalkan citra lamanya yang lambat dan kini menawarkan kecepatan tinggi.

    • Performa Ruby meningkat drastis berkat inovasi seperti teknologi YJIT, object shapes, dan optimasi GC.
    • Perusahaan besar pengguna Ruby seperti Shopify juga telah merasakan peningkatan performa di Ruby 3.3.
    • Secara pribadi sangat menantikan masa depan Ruby, dan antusias untuk menerapkan Ruby 3.3 ke situs produksi pelanggan.
  • Ruby 3.3 disebut sebagai rilis paling penting dan paling kaya fitur dalam 10 tahun terakhir, dan ada rasa heran karena Ruby merilis JIT lebih dulu daripada Python.

    • Berbagai fitur seperti Prism, Lrama, dan IRB telah dibahas dalam kiriman Hacker News sebelumnya.
    • Fitur seperti Ractor, scheduler thread M:N, Fibre, dan Async dinilai belum cukup banyak dibahas dalam konteks Rails, dan ada keinginan untuk mendengar pengalaman orang-orang yang menggunakannya di produksi.
  • Disebutkan bahwa Ruby 3.3 sudah bisa digunakan di Heroku.

  • Setiap tahun saat Natal, bahasa Ruby merilis versi baru.

  • Ada pertanyaan apakah mempelajari Ruby masih bernilai jika sudah menguasai Python dan NodeJS. Ruby terasa menarik, tetapi juga terasa sulit.

  • Resolusi nama seperti Socket.getaddrinfo dapat memblokir. Setiap kali perlu melakukan resolusi nama, Ruby membuat worker pthread dan menjalankan getaddrinfo(3).

    • Ada pertanyaan apakah runtime bahasa lain juga melakukan hal serupa. Pembuatan thread mungkin terasa berat, tetapi menurut benchmark, overhead-nya sangat kecil.
  • Prism terasa menarik. Ada pertanyaan apakah sudah ada contoh penggunaan Prism sebagai alat analisis kode Ruby.

  • Variabel environment RUBY_MAX_CPU=n menetapkan jumlah maksimum native thread. Nilai default-nya adalah 8.

    • Muncul pertanyaan apakah nilai default seharusnya sama dengan jumlah logical core, seperti di Tokio milik Rust dan banyak runtime M:N lainnya.
  • Sedang mencari tautan ke contoh yang bagus menggunakan Prism. Ada rasa kecewa karena di halaman rilis tidak banyak yang terlihat selain "API yang patut diperhatikan".

  • Disebut sebagai hadiah Natal yang sempurna.