Phát hành Ruby 3.0.0

Đăng bởi naruse vào 25 Dec 2020

Chúng tôi vui mừng thông báo phát hành Ruby 3.0.0. Từ năm 2015, chúng tôi đã nỗ lực phát triển Ruby 3, với mục tiêu về hiệu năng, đồng thời và kiểu dữ liệu. Đặc biệt về hiệu năng, Matz đã tuyên bố “Ruby3 sẽ nhanh gấp 3 lần Ruby2” hay còn gọi là Ruby 3x3.

Optcarrot 3000 frames

Với benchmark Optcarrot, đo hiệu năng đơn luồng dựa trên khối lượng công việc mô phỏng trò chơi NES, Ruby đã đạt hiệu năng nhanh gấp 3 lần so với Ruby 2.0!

Các phép đo được thực hiện trong môi trường được ghi chú tại benchmark-driver.github.io/hardware.html. Commit 8c510e4095 được sử dụng làm Ruby 3.0. Tốc độ có thể không nhanh gấp 3 lần tùy thuộc vào môi trường hoặc benchmark của bạn.

Ruby 3.0.0 đạt được các mục tiêu đó thông qua

  • Hiệu năng
    • MJIT
  • Đồng thời
    • Ractor
    • Fiber Scheduler
  • Kiểu dữ liệu (Phân tích tĩnh)
    • RBS
    • TypeProf

Với cải thiện hiệu năng ở trên, Ruby 3.0 giới thiệu một số tính năng mới được mô tả dưới đây.

Hiệu năng

Khi tôi lần đầu tuyên bố “Ruby3x3” trong bài phát biểu chính tại hội nghị, nhiều người kể cả thành viên đội ngũ core đã cảm thấy “Matz nói khoác”. Thực tế, tôi cũng cảm thấy vậy. Nhưng chúng tôi đã làm được. Tôi vinh dự khi thấy đội ngũ core thực sự đã hoàn thành việc làm cho Ruby3.0 nhanh gấp ba lần Ruby2.0 (trong một số benchmark). – Matz

MJIT

Nhiều cải tiến đã được thực hiện trong MJIT. Xem NEWS để biết chi tiết.

Tính đến Ruby 3.0, JIT được cho là cải thiện hiệu năng trong các khối lượng công việc giới hạn, chẳng hạn như trò chơi (Optcarrot), AI (Rubykon), hoặc bất kỳ ứng dụng nào dành phần lớn thời gian để gọi một vài phương thức nhiều lần.

Mặc dù Ruby 3.0 đã giảm đáng kể kích thước mã JIT-ed, nó vẫn chưa sẵn sàng để tối ưu hóa các khối lượng công việc như Rails, vốn thường dành thời gian cho rất nhiều phương thức và do đó bị ảnh hưởng bởi i-cache miss bị trầm trọng hóa bởi JIT. Hãy đón chờ Ruby 3.1 để có thêm cải tiến về vấn đề này.

Đồng thời / Song song

Đây là thời đại đa nhân. Đồng thời là rất quan trọng. Với Ractor, cùng với Async Fiber, Ruby sẽ trở thành ngôn ngữ đồng thời thực sự. — Matz

Ractor (thử nghiệm)

Ractor là một abstraction đồng thời theo mô hình Actor, được thiết kế để cung cấp tính năng thực thi song song mà không lo ngại về an toàn luồng.

Bạn có thể tạo nhiều ractor và chạy chúng song song. Ractor cho phép bạn tạo các chương trình song song an toàn luồng vì các ractor không thể chia sẻ các đối tượng thông thường. Giao tiếp giữa các ractor được hỗ trợ thông qua trao đổi tin nhắn.

Để giới hạn việc chia sẻ đối tượng, Ractor đưa ra một số hạn chế đối với cú pháp Ruby (không có nhiều Ractor thì không có hạn chế).

Đặc tả và triển khai chưa hoàn thiện và có thể thay đổi trong tương lai, vì vậy tính năng này được đánh dấu là thử nghiệm và hiển thị cảnh báo “tính năng thử nghiệm” khi Ractor.new đầu tiên được gọi.

Chương trình nhỏ sau đo thời gian thực thi của hàm benchmark nổi tiếng tak (Tak (function) - Wikipedia), bằng cách thực thi nó 4 lần tuần tự hoặc 4 lần song song với ractor.

def tarai(x, y, z) =
  x <= y ? y : tarai(tarai(x-1, y, z),
                     tarai(y-1, z, x),
                     tarai(z-1, x, y))
require 'benchmark'
Benchmark.bm do |x|
  # sequential version
  x.report('seq'){ 4.times{ tarai(14, 7, 0) } }

  # parallel version
  x.report('par'){
    4.times.map do
      Ractor.new { tarai(14, 7, 0) }
    end.each(&:take)
  }
end
Benchmark result:
          user     system      total        real
seq  64.560736   0.001101  64.561837 ( 64.562194)
par  66.422010   0.015999  66.438009 ( 16.685797)

Kết quả được đo trên Ubuntu 20.04, Intel(R) Core(TM) i7-6700 (4 lõi, 8 luồng phần cứng). Cho thấy phiên bản song song nhanh gấp 3.87 lần so với phiên bản tuần tự.

Xem doc/ractor.md để biết thêm chi tiết.

Fiber Scheduler

Fiber#scheduler được giới thiệu để chặn các thao tác blocking. Điều này cho phép đồng thời nhẹ mà không cần thay đổi mã hiện tại. Xem “Don’t Wait For Me, Scalable Concurrency for Ruby 3” để có cái nhìn tổng quan về cách hoạt động.

Các lớp/phương thức hiện đang được hỗ trợ:

  • Mutex#lock, Mutex#unlock, Mutex#sleep
  • ConditionVariable#wait
  • Queue#pop, SizedQueue#push
  • Thread#join
  • Kernel#sleep
  • Process.wait
  • IO#wait, IO#read, IO#write, và các phương thức liên quan (ví dụ: #wait_readable, #gets, #puts, v.v.).
  • IO#select không được hỗ trợ.

Chương trình ví dụ này sẽ thực hiện nhiều request HTTP đồng thời:

require 'async'
require 'net/http'
require 'uri'

Async do
  ["ruby", "rails", "async"].each do |topic|
    Async do
      Net::HTTP.get(URI "https://www.google.com/search?q=#{topic}")
    end
  end
end

Nó sử dụng async cung cấp vòng lặp sự kiện. Vòng lặp sự kiện này sử dụng các hook Fiber#scheduler để làm Net::HTTP non-blocking. Các gem khác có thể sử dụng giao diện này để cung cấp thực thi non-blocking cho Ruby, và các gem đó có thể tương thích với các triển khai khác của Ruby (ví dụ: JRuby, TruffleRuby) hỗ trợ cùng các hook non-blocking.

Phân tích tĩnh

Thập niên 2010 là thời đại của các ngôn ngữ lập trình kiểu tĩnh. Ruby tìm kiếm tương lai với kiểm tra kiểu tĩnh, mà không cần khai báo kiểu, sử dụng diễn giải trừu tượng. RBS & TypeProf là bước đầu tiên hướng tới tương lai. Sẽ còn nhiều bước tiếp theo. — Matz

RBS

RBS là một ngôn ngữ để mô tả kiểu dữ liệu của chương trình Ruby.

Các công cụ kiểm tra kiểu bao gồm TypeProf và các công cụ khác hỗ trợ RBS sẽ hiểu chương trình Ruby tốt hơn nhiều với các định nghĩa RBS.

Bạn có thể viết định nghĩa cho các lớp và module: các phương thức được định nghĩa trong lớp, biến instance và kiểu dữ liệu của chúng, cũng như các quan hệ kế thừa/mix-in.

Mục tiêu của RBS là hỗ trợ các mẫu thường thấy trong chương trình Ruby và cho phép viết các kiểu nâng cao bao gồm kiểu union, nạp chồng phương thức và generic. RBS cũng hỗ trợ duck typing với kiểu interface.

Ruby 3.0 đi kèm với gem rbs, cho phép phân tích và xử lý các định nghĩa kiểu được viết bằng RBS. Dưới đây là một ví dụ nhỏ về RBS với các định nghĩa lớp, module và hằng số.

module ChatApp
  VERSION: String
  class Channel
    attr_reader name: String
    attr_reader messages: Array[Message]
    attr_reader users: Array[User | Bot]              # `|` means union types, `User` or `Bot`.
    def initialize: (String) -> void
    def post: (String, from: User | Bot) -> Message   # Method overloading is supported.
            | (File, from: User | Bot) -> Message
  end
end

Xem README của gem rbs để biết thêm chi tiết.

TypeProf

TypeProf là một công cụ phân tích kiểu được đi kèm trong gói Ruby.

Hiện tại, TypeProf hoạt động như một loại suy luận kiểu.

Nó đọc mã Ruby thuần (không có chú thích kiểu), phân tích các phương thức được định nghĩa và cách chúng được sử dụng, và tạo ra một bản mẫu chữ ký kiểu ở định dạng RBS.

Đây là một demo đơn giản về TypeProf.

Đầu vào mẫu:

# test.rb
class User
  def initialize(name:, age:)
    @name, @age = name, age
  end
  attr_reader :name, :age
end
User.new(name: "John", age: 20)

Đầu ra mẫu:

$ typeprof test.rb
# Classes
class User
  attr_reader name : String
  attr_reader age : Integer
  def initialize : (name: String, age: Integer) -> [String, Integer]
end

Bạn có thể chạy TypeProf bằng cách lưu đầu vào thành “test.rb” và gọi lệnh “typeprof test.rb”.

Bạn cũng có thể thử TypeProf trực tuyến. (Nó chạy TypeProf ở phía máy chủ, xin lỗi nếu không hoạt động!)

Xem tài liệu TypeProfdemo để biết chi tiết.

TypeProf đang trong giai đoạn thử nghiệm và chưa hoàn thiện; chỉ một tập con của ngôn ngữ Ruby được hỗ trợ, và khả năng phát hiện lỗi kiểu còn hạn chế. Nhưng nó đang phát triển nhanh chóng để cải thiện phạm vi hỗ trợ các tính năng ngôn ngữ, hiệu suất phân tích và tính dễ sử dụng. Mọi phản hồi đều được hoan nghênh.

Các tính năng mới đáng chú ý khác

  • Khớp mẫu một dòng được thiết kế lại. (thử nghiệm)

    • => đã được thêm vào. Nó có thể được sử dụng như phép gán hướng phải.

      0 => a
      p a #=> 0
      
      {b: 0, c: 1} => {b:}
      p b #=> 0
      
    • in được thay đổi để trả về true hoặc false.

      # version 3.0
      0 in 1 #=> false
      
      # version 2.7
      0 in 1 #=> raise NoMatchingPatternError
      
  • Mẫu tìm kiếm (find pattern) đã được thêm vào. (thử nghiệm)

    case ["a", 1, "b", "c", 2, "d", "e", "f", 3]
    in [*pre, String => x, String => y, *post]
      p pre  #=> ["a", 1]
      p x    #=> "b"
      p y    #=> "c"
      p post #=> [2, "d", "e", "f", 3]
    end
    
  • Định nghĩa phương thức không kết thúc đã được thêm vào.

    def square(x) = x * x
    
  • Hash#except giờ đã có sẵn.

    h = { a: 1, b: 2, c: 3 }
    p h.except(:a) #=> {:b=>2, :c=>3}
    
  • Memory view đã được thêm như một tính năng thử nghiệm

    • Đây là một bộ C-API mới để trao đổi vùng bộ nhớ thô, chẳng hạn như mảng số hoặc ảnh bitmap, giữa các thư viện mở rộng. Các thư viện mở rộng cũng có thể chia sẻ metadata của vùng bộ nhớ bao gồm hình dạng, định dạng phần tử, v.v. Sử dụng những loại metadata này, các thư viện mở rộng có thể chia sẻ ngay cả mảng đa chiều một cách phù hợp. Tính năng này được thiết kế tham khảo từ buffer protocol của Python.

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

  • Dán mã dài vào IRB nhanh hơn 53 lần so với phiên bản đi kèm Ruby 2.7.0. Ví dụ, thời gian cần thiết để dán mã mẫu này giảm từ 11.7 giây xuống 0.22 giây.
  • Lệnh measure đã được thêm vào IRB. Nó cho phép đo thời gian thực thi đơn giản.

    irb(main):001:0> 3
    => 3
    irb(main):002:0> measure
    TIME is added.
    => nil
    irb(main):003:0> 3
    processing time: 0.000058s
    => 3
    irb(main):004:0> measure :off
    => nil
    irb(main):005:0> 3
    => 3
    

Các thay đổi đáng chú ý khác kể từ 2.7

  • Tham số từ khóa được tách riêng khỏi các tham số khác.
    • Về nguyên tắc, mã hiển thị cảnh báo trên Ruby 2.7 sẽ không hoạt động. Xem tài liệu này để biết chi tiết.
    • Ngoài ra, chuyển tiếp tham số giờ đã hỗ trợ tham số đứng đầu.

      def method_missing(meth, ...)
        send(:"do_#{ meth }", ...)
      end
      
  • Khớp mẫu (case/in) không còn là thử nghiệm.
  • Tính năng $SAFE đã bị loại bỏ hoàn toàn; giờ nó là một biến toàn cục bình thường.
  • Thứ tự backtrace đã bị đảo ngược ở Ruby 2.5; thay đổi này đã được hoàn tác. Giờ backtrace hoạt động như Ruby 2.4: thông báo lỗi và số dòng nơi ngoại lệ xảy ra được in trước, và các hàm gọi được in sau.
  • Một số thư viện chuẩn đã được cập nhật.
    • RubyGems 3.2.3
    • Bundler 2.2.3
    • IRB 1.3.0
    • Reline 0.2.0
    • Psych 3.3.0
    • JSON 2.5.1
    • BigDecimal 3.0.0
    • CSV 3.1.9
    • Date 3.1.0
    • Digest 3.0.0
    • Fiddle 1.0.6
    • StringIO 3.0.0
    • StringScanner 3.0.0
    • v.v.
  • Các thư viện sau không còn là bundled gem hoặc thư viện chuẩn. Cài đặt các gem tương ứng để sử dụng các tính năng này.
    • sdbm
    • webrick
    • net-telnet
    • xmlrpc
  • Các default gem sau giờ là bundled gem.
    • rexml
    • rss
  • Các tệp stdlib sau giờ là default gem và được xuất bản trên rubygems.org.
    • English
    • abbrev
    • base64
    • drb
    • debug
    • erb
    • find
    • net-ftp
    • net-http
    • net-imap
    • net-protocol
    • open-uri
    • optparse
    • pp
    • prettyprint
    • resolv-replace
    • resolv
    • rinda
    • set
    • securerandom
    • shellwords
    • tempfile
    • tmpdir
    • time
    • tsort
    • un
    • weakref
    • digest
    • io-nonblock
    • io-wait
    • nkf
    • pathname
    • syslog
    • win32ole

Xem NEWS hoặc nhật ký commit để biết thêm chi tiết.

Với những thay đổi đó, 4028 tệp đã thay đổi, 200058 thêm vào(+), 154063 xóa bỏ(-) kể từ Ruby 2.7.0!

Ruby3.0 là một cột mốc. Ngôn ngữ đã tiến hóa, giữ được tính tương thích. Nhưng đây không phải là kết thúc. Ruby sẽ tiếp tục phát triển, và trở nên tuyệt vời hơn nữa. Hãy đón chờ! — Matz

Chúc Giáng sinh vui vẻ, Kỳ nghỉ hạnh phúc, và hãy tận hưởng lập trình với Ruby 3.0!

Tải về

  • https://cache.ruby-lang.org/pub/ruby/3.0/ruby-3.0.0.tar.gz

    SIZE: 19539509
    SHA1: 233873708c1ce9fdc295e0ef1c25e64f9b98b062
    SHA256: a13ed141a1c18eb967aac1e33f4d6ad5f21be1ac543c344e0d6feeee54af8e28
    SHA512: e62f4f63dc12cff424e8a09adc06477e1fa1ee2a9b2b6e28ca22fd52a211e8b8891c0045d47935014a83f2df2d6fc7c8a4fd87f01e63c585afc5ef753e1dd1c1
    
  • https://cache.ruby-lang.org/pub/ruby/3.0/ruby-3.0.0.tar.xz

    SIZE: 14374176
    SHA1: c142899d70a1326c5a71311b17168f98c15e5d89
    SHA256: 68bfaeef027b6ccd0032504a68ae69721a70e97d921ff328c0c8836c798f6cb1
    SHA512: 2a23c2894e62e24bb20cec6b2a016b66d7df05083668726b6f70af8338211cfec417aa3624290d1f5ccd130f65ee7b52b5db7d428abc4a9460459c9a5dd1a450
    
  • https://cache.ruby-lang.org/pub/ruby/3.0/ruby-3.0.0.zip

    SIZE: 23862057
    SHA1: 2a9629102d71c7fe7f31a8c91f64e570a40d093c
    SHA256: a5e4fa7dc5434a7259e9a29527eeea2c99eeb5e82708f66bb07731233bc860f4
    SHA512: e5bf742309d79f05ec1bd1861106f4b103e4819ca2b92a826423ff451465b49573a917cb893d43a98852435966323e2820a4b9f9377f36cf771b8c658f80fa5b
    

Ruby là gì

Ruby được phát triển lần đầu bởi Matz (Yukihiro Matsumoto) vào năm 1993 và hiện được phát triển dưới dạng Mã nguồn Mở. Nó chạy trên nhiều nền tảng và được sử dụng trên toàn thế giới, đặc biệt cho phát triển web.

Tin mới nhất

Phát hành Ruby 4.0.0

Chúng tôi vui mừng thông báo phát hành Ruby 4.0.0. Ruby 4.0 giới thiệu “Ruby Box” và “ZJIT”, cùng nhiều cải tiến khác.

Đăng bởi naruse vào 25 Dec 2025

Diện mạo mới cho tài liệu Ruby

Tiếp theo việc thiết kế lại ruby-lang.org, chúng tôi có thêm tin vui để kỷ niệm 30 năm Ruby: docs.ruby-lang.org có diện mạo hoàn toàn...

Đăng bởi Stan Lo vào 23 Dec 2025

Thêm Tin...