Freeze trong Ruby
Thời gian gần đây, khi đọc một số bài viết về ROR của các blogger hay trên các diễn đàn công nghệ, thì bắt gặp việc các developer sử dụng freeze ngày càng nhiều. Bài viết này được viết với hy vọng người đọc sẽ tìm được lời giải thích hợp lí cho việc tại sao phải dùng, và dùng freeze thế nào cho ...
Thời gian gần đây, khi đọc một số bài viết về ROR của các blogger hay trên các diễn đàn công nghệ, thì bắt gặp việc các developer sử dụng freeze ngày càng nhiều. Bài viết này được viết với hy vọng người đọc sẽ tìm được lời giải thích hợp lí cho việc tại sao phải dùng, và dùng freeze thế nào cho hiệu quả Bắt đầu hiểu từng bước nhé.
1. Tạo hằng số
Trong Ruby, hằng số có thể thay đổi
MY_CONSTANT = "cn" MY_CONSTANT << "15" puts MY_CONSTANT.inspect # => "cn15"
Nhưng bằng cách sử dụng freeze, ta sẽ tạo được một hằng số thực sự, đó là hằng số không thể thay đổi, và khi cố gắng thay đổi nó ta sẽ nhận được thông báo lỗi như thế này.
MY_CONSTANT = "cn".freeze MY_CONSTANT << "15" # => RuntimeError: can't modify frozen string
2. Câu chuyện tối ưu
Một trong những cách tốt nhất để tăng tốc ứng dụng Ruby đó là giảm số lượng các object được tạo ra. Mỗi lần bạn sử dụng method log("cn15"), bạn sẽ tạo một đối tượng string. Nếu code của bạn gọi nó một trăm lần 1 giây, có nghĩa là bạn đang tạo hàng trăm string 1 giây.
Nếu chúng ta dùng freeze với các string này, Ruby sẽ chỉ tạo ra một đối tượng string và cache chúng lại cho lần sử dụng sau. Chỉ số benchmark:
require 'benchmark/ips' def noop(arg) end Benchmark.ips do |x| x.report("normal") { noop("foo") } x.report("frozen") { noop("foo".freeze) } end Results with MRI 2.2.2: Calculating ------------------------------------- normal 152.123k i/100ms frozen 167.474k i/100ms ------------------------------------------------- normal 6.158M (± 3.3%) i/s - 30.881M frozen 9.312M (± 3.5%) i/s - 46.558M
Ruby 2.2 trở đi sẽ tự động freeze string khi sử dụng string làm key của hash
user = {"name" => "cn"} user["name"] mà không cần phải user["name".freeze]
3. Đảm bảo giá trị của đối tượng
Bằng cách sử dụng freeze bên trong constructor, ta có thể đảm bảo đối tượng sẽ không thể thay đổi, và mọi tác động bên ngoài sẽ đều báo lỗi.
class Point attr_accessor :x, :y def initialize(x, y) @x = x @y = y freeze end def change @x = 15 end end point = Point.new(1,2) point.change # RuntimeError: can't modify frozen Point
Nguồn: http://blog.honeybadger.io/when-to-use-freeze-and-frozen-in-ruby/