1 điểm bởi GN⁺ 2023-12-26 | 1 bình luận | Chia sẻ qua WhatsApp

Ruby 3.3.0 phát hành

  • Phiên bản Ruby 3.3.0 đã được phát hành. Bản này giới thiệu Prism, trình phân tích cú pháp mới; sử dụng Lrama làm trình sinh parser; bổ sung RJIT, trình biên dịch JIT viết hoàn toàn bằng Ruby; và đặc biệt cải thiện hiệu năng của YJIT.

Trình phân tích cú pháp Prism

  • Prism là trình phân tích cú pháp đệ quy xuống, có thể di chuyển, chịu lỗi tốt và dễ bảo trì cho ngôn ngữ Ruby, được cung cấp dưới dạng gem mặc định.
  • Prism phù hợp cho môi trường production, đang được bảo trì tích cực và có thể dùng để thay thế Ripper.
  • Có tài liệu chi tiết về cách sử dụng Prism.
  • Prism vừa là thư viện C được dùng bên trong CRuby, vừa là gem Ruby có thể được dùng trong mọi công cụ cần phân tích mã Ruby.
  • Các phương thức chính của API Prism gồm Prism.parse(source), Prism.parse_comments(source), Prism.parse_success?(source).
  • Có thể đóng góp trực tiếp bằng cách gửi pull request hoặc issue vào kho lưu trữ Prism.
  • Để thử nghiệm trình biên dịch Prism, có thể dùng ruby --parser=prism hoặc RUBYOPT="--parser=prism", nhưng chỉ nên dùng cho mục đích gỡ lỗi.

Trình sinh parser Lrama

  • Thay thế Bison bằng trình sinh parser LALR Lrama.
  • Những ai quan tâm có thể tham khảo tầm nhìn tương lai cho parser của Ruby.
  • Để dễ bảo trì, parser Lrama nội bộ được thay bằng parser LR do Racc tạo ra.
  • Hỗ trợ các quy tắc có tham số (?, *, +), dự kiến sẽ được dùng trong Ruby parse.y.

YJIT

  • Có nhiều cải tiến hiệu năng đáng kể so với Ruby 3.2.
  • Cải thiện hỗ trợ cho đối số splat và rest.
  • Thanh ghi được gán cho các thao tác stack của máy ảo.
  • Nhiều lời gọi có đối số tùy chọn hơn được biên dịch. Trình xử lý ngoại lệ cũng được biên dịch.
  • Các kiểu lời gọi chưa được hỗ trợ và các call site megamorphic không còn quay về interpreter nữa.
  • Các phương thức cơ bản như #blank? của Rails và #present? theo trường hợp đặc biệt được inline.
  • Integer#*, Integer#!=, String#!=, String#getbyte, Kernel#block_given?, Kernel#is_a?, Kernel#instance_of?, Module#=== và nhiều mục khác được tối ưu hóa đặc biệt.
  • Tốc độ biên dịch nhanh hơn một chút so với Ruby 3.2.
  • Trên Optcarrot, nhanh hơn interpreter hơn 3 lần.
  • Mức sử dụng bộ nhớ được cải thiện đáng kể so với Ruby 3.2.
  • Metadata của mã đã biên dịch dùng ít bộ nhớ hơn rất nhiều.
  • --yjit-call-threshold tự động tăng từ 30 lên 120 đối với các ứng dụng có hơn 40.000 ISEQ.
  • Thêm --yjit-cold-threshold để bỏ qua việc biên dịch các ISEQ đã nguội.
  • Tạo ra mã gọn hơn trên Arm64.
  • Code GC bị tắt theo mặc định.
  • --yjit-exec-mem-size được xử lý như giới hạn cứng để dừng biên dịch mã mới.
  • Không còn suy giảm hiệu năng do code GC, và khi dùng Pitchfork, máy chủ có hành vi copy-on-write tốt hơn khi re-fork.
  • Nếu muốn, có thể bật code GC bằng --yjit-code-gc.
  • Bổ sung RubyVM::YJIT.enable để bật YJIT trong thời gian chạy.
  • Rails 7.2 dự kiến sẽ dùng cách này để bật YJIT theo mặc định.
  • Có thể dùng cách này để chỉ bật YJIT sau khi ứng dụng khởi động xong.
  • Nếu muốn tắt YJIT khi khởi động nhưng vẫn dùng các tùy chọn YJIT khác, có thể dùng --yjit-disable.
  • Mặc định cung cấp nhiều thống kê YJIT hơn.
  • yjit_alloc_size và nhiều thống kê liên quan đến metadata hiện có sẵn theo mặc định.
  • Thống kê ratio_in_yjit do --yjit-stats tạo ra hiện dùng được trong bản build phát hành. Không còn cần build thống kê đặc biệt hoặc build phát triển.
  • Thêm nhiều khả năng profiling hơn.
  • --yjit-perf được thêm vào để giúp profiling dễ hơn với Linux perf.
  • --yjit-trace-exits hỗ trợ lấy mẫu với --yjit-trace-exits-sample-rate=N.
  • Có thêm kiểm thử kỹ lưỡng và nhiều bản sửa lỗi.

RJIT

  • Giới thiệu RJIT, trình biên dịch JIT viết thuần Ruby, thay thế MJIT.
  • RJIT chỉ được hỗ trợ trên kiến trúc x86-64 của nền tảng Unix.
  • Khác với MJIT, không cần trình biên dịch C trong thời gian chạy.
  • RJIT chỉ tồn tại cho mục đích thử nghiệm.
  • Trong môi trường production, vẫn nên tiếp tục dùng YJIT.
  • Nếu quan tâm đến phát triển Ruby JIT, nên xem bài trình bày của k0kubun vào ngày thứ 3 của RubyKaigi.

Bộ lập lịch luồng M:N

  • Bộ lập lịch luồng M:N được giới thiệu.
  • M luồng Ruby được quản lý bởi N luồng native (luồng của hệ điều hành), giúp giảm chi phí tạo và quản lý luồng.
  • Bộ lập lịch luồng M:N bị tắt theo mặc định trong Ractor chính vì có thể phá vỡ tính tương thích với các phần mở rộng C.
  • Có thể bật luồng M:N trong Ractor chính bằng biến môi trường RUBY_MN_THREADS=1.
  • Trong các Ractor không phải chính, luồng M:N luôn được bật.
  • Biến môi trường RUBY_MAX_CPU=n đặt số lượng tối đa của N (số luồng native tối đa). Mặc định là 8.
  • Vì mỗi Ractor chỉ có thể chạy một luồng Ruby tại một thời điểm, các ứng dụng một Ractor (đa số ứng dụng) chỉ dùng 1 luồng native.
  • Có thể dùng nhiều hơn N luồng native để hỗ trợ các tác vụ chặn.

Cải thiện hiệu năng

  • defined?(@ivar) được tối ưu bằng Object Shapes.
  • Việc phân giải tên như Socket.getaddrinfo nay có thể bị ngắt (trong các môi trường hỗ trợ pthreads).
  • Có nhiều cải tiến hiệu năng cho garbage collector.
    • Khi đối tượng trẻ được đối tượng già tham chiếu, nó không còn bị đẩy ngay lên thế hệ già, giúp giảm mạnh tần suất major GC.
    • Thêm biến tinh chỉnh mới REMEMBERED_WB_UNPROTECTED_OBJECTS_LIMIT_RATIO để kiểm soát số lượng đối tượng không được bảo vệ gây ra major GC. Giá trị mặc định là 0.01 (1%), giúp giảm mạnh tần suất major GC.
    • Đã triển khai Write Barriers cho nhiều kiểu lõi còn thiếu. Điều này giúp giảm đáng kể thời gian minor GC và tần suất major GC.
    • Hầu hết các lớp lõi hiện dùng Variable Width Allocation. Nhờ đó việc cấp phát và giải phóng của các lớp này nhanh hơn, giảm sử dụng bộ nhớ và giảm phân mảnh heap.
    • Bổ sung hỗ trợ weak reference cho garbage collector.

Các thay đổi đáng chú ý khác

  • IRB nhận được nhiều cải tiến, gồm tích hợp nâng cao irb:rdbg, hỗ trợ pager cho các lệnh ls, show_source và show_cmds, cải thiện độ chính xác và tính hữu ích của thông tin do lệnh ls và show_source cung cấp, cùng với tự động hoàn thành thử nghiệm dùng phân tích kiểu.
  • IRB cũng được refactor trên diện rộng để hỗ trợ các cải tiến trong tương lai và nhận hàng chục bản sửa lỗi.

Vấn đề tương thích

  • Việc gọi it trong block mà không có đối số không còn được dùng nữa; trong Ruby 3.4, nó sẽ tham chiếu đến tham số block đầu tiên.
  • Các biến môi trường không còn dùng đã bị loại bỏ.

Cập nhật thư viện chuẩn

  • RubyGems và Bundler sẽ hiển thị cảnh báo nếu người dùng yêu cầu các gem sau mà không thêm chúng vào Gemfile hoặc gemspec. Điều này là do các gem đó sẽ trở thành bundled gem trong các phiên bản Ruby tương lai.
  • Nhiều default gem đã được thêm mới hoặc cập nhật, như prism 0.19.0, RubyGems 3.5.3, abbrev 0.1.2 và nhiều mục khác.
  • Nhiều bundled gem được nâng từ default gem hoặc được cập nhật, như racc 1.7.3, minitest 5.20.0 và nhiều mục khác.

Ý kiến của GN⁺

  • Giới thiệu parser Prism: Một trong những điểm nổi bật quan trọng nhất của Ruby 3.3.0 là việc giới thiệu parser Prism mới. Điều này sẽ giúp các lập trình viên Ruby rất nhiều bằng cách cung cấp một parser xử lý mã Ruby hiệu quả hơn, chịu lỗi tốt hơn và dễ bảo trì hơn.
  • Cải thiện hiệu năng của YJIT: Những cải thiện hiệu năng lớn của YJIT sẽ nâng đáng kể tốc độ thực thi của các ứng dụng Ruby; đặc biệt, việc giảm sử dụng bộ nhớ và tối ưu GC sẽ tác động tích cực đến hiệu năng và độ ổn định của các ứng dụng Ruby quy mô lớn.
  • Bộ lập lịch luồng M:N: Việc giới thiệu bộ lập lịch luồng M:N có tiềm năng cải thiện hiệu năng cho các ứng dụng Ruby đa luồng. Nó sẽ giảm chi phí quản lý luồng và cho phép xử lý song song hiệu quả hơn.

1 bình luận

 
GN⁺ 2023-12-26
Ý kiến trên Hacker News
  • Với sự xuất hiện của Ruby 3.3, Ruby — ngôn ngữ đề cao niềm vui của lập trình viên — đã thoát khỏi hình ảnh chậm chạp trước đây và nay tự hào với tốc độ nhanh hơn.

    • Hiệu năng của Ruby đã được cải thiện đáng kể nhờ những đổi mới như công nghệ YJIT, object shapes và tối ưu hóa GC.
    • Các công ty lớn sử dụng Ruby như Shopify đang trải nghiệm những cải thiện hiệu năng của Ruby 3.3.
    • Cá nhân rất kỳ vọng vào tương lai của Ruby và bày tỏ sự háo hức khi áp dụng Ruby 3.3 cho các site production của khách hàng.
  • Ruby 3.3 là bản phát hành quan trọng và nhiều tính năng nhất trong 10 năm qua, đồng thời bày tỏ sự ngạc nhiên khi Ruby phát hành JIT trước cả Python.

    • Nhiều tính năng như Prism, Lrama, IRB đã được thảo luận trong các bài đăng Hacker News trước đó.
    • Các tính năng như Ractor, bộ lập lịch luồng M:N, Fibre, Async chưa được nhắc đến đầy đủ trong bối cảnh Rails, và muốn nghe trải nghiệm từ những người đang dùng chúng trong production.
  • Thông báo rằng có thể sử dụng Ruby 3.3 trên Heroku.

  • Ruby phát hành bản release mới vào mỗi dịp Giáng sinh hằng năm.

  • Đặt câu hỏi liệu có đáng học Ruby hay không nếu đã biết Python và NodeJS. Cảm thấy Ruby hấp dẫn nhưng cũng khó.

  • Việc phân giải tên như Socket.getaddrinfo có thể bị chặn. Mỗi khi cần phân giải tên, nó tạo một worker pthread và chạy getaddrinfo(3).

    • Đặt câu hỏi liệu runtime của các ngôn ngữ khác có làm điều tương tự không. Việc tạo thread có thể cảm thấy nặng, nhưng theo benchmark thì overhead là tối thiểu.
  • Prism khá thú vị. Đặt câu hỏi liệu có ví dụ nào dùng Prism như một công cụ phân tích mã Ruby hay không.

  • Biến môi trường RUBY_MAX_CPU=n đặt số lượng tối đa của native thread. Giá trị mặc định là 8.

    • Nêu thắc mắc liệu giá trị mặc định có nên bằng số lượng lõi logic hay không, giống như Tokio của Rust và nhiều runtime M:N khác.
  • Đang tìm link đến các ví dụ hay dùng Prism. Thất vọng vì ngoài phần "API đáng chú ý" trên trang phát hành thì không thấy gì nhiều.

  • Nhắc rằng đây là món quà Giáng sinh hoàn hảo.