12/08/2018, 15:21

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/

0