Ruby Hash[key] So sánh :symbol và “string”
Bài đăng này đã không được cập nhật trong 3 năm
Ai sẽ quan tâm?
Gần đây có một cuộc thảo luận trên kênh Trailblazer Gitter về Hashes như một params, làm thế nào để gán chúng, và như thường lệ một cuộc tranh luận bùng nổ và nó đã tạo ra một cuộc thi đo lường: cách nào tốt hơn và nhanh hơn.
Đối với những người thiếu kiên nhẫn: về hash nhỏ sẽ không có gì quan trọng; về hash lớn: symbol nhanh hơn string khá nhiều trong khi frozen string xấp xỉ symbol.
Cách tốt nhất để tranh luận, là đưa ra các bằng chứng. Vì vậy, tôi có viết 1 đoạn code nhỏ để so sánh. Cụ thể ở đây (Github).
Lượt 1: Hash[:symbol] với Hash[“string”]
Đầu tiên, tạo ra các hash theo cách của Ruby
require "benchmark/ips"
def symbol_key
{symbol: 42}
end
def symbol_key_arrow
{:symbol => 42}
end
def symbol_key_in_string_form
{'sym_str': 42}
end
def string_key_arrow_double_quotes
{"string" => 42}
end
def string_key_arrow_single_quotes
{'string' => 42}
end
Toàn bộ code của phần này có sẵn trên Github, các bạn có thể thử trên máy của mình. Kết quả trên đây được ghi nhận từ máy tính của tôi với cấu hình sau:
Comparison:
{symbol: 42}: 3068310.2 i/s
{'sym_str': 42}: 3154171.0 i/s - same-ish
{:symbol => 42}: 3107735.4 i/s - same-ish
{'string' => 42}: 2997402.4 i/s - 1.05x slower
{"string" => 42}: 2981802.5 i/s - 1.06x slower
Dù lặp tới gần 3 triệu vòng/giây nhưng cũng chỉ chậm hơn 5 - 6% nên sẽ chẳng ai quan tâm đến việc này phải không?
string keys không làm giảm tốc độ ứng dụng của bạn.
Lượt 2: Với những hash lớn thì sao?
Cùng thử với 1000 cặp key - value. Bạn có thể xem code cụ thể phần này ở Github.
require "benchmark/ips"
STRING_KEYS = (1..1000).map{"x" "key_#{x}"}.shuffle
FROZEN_KEYS = STRING_KEYS.map{x "fr_#{x}".freeze}
SYMBOL_KEYS = STRING_KEYS.map(&:to_sym)
def symbol_hash
SYMBOL_KEYS.collect { "k" [ k, rand(1..100)]}.to_h
end
def string_hash
STRING_KEYS.collect { k [ k, rand(1..100)]}.to_h
end
def frozen_hash
FROZEN_KEYS.collect { "k" [ k, rand(1..100)]}.to_h
end
SYMBOL_HASH = symbol_hash
STRING_HASH = string_hash
FROZEN_HASH = frozen_hash
def reading_symbol_hash
SYMBOL_HASH[SYMBOL_KEYS.sample]
end
def reading_string_hash
STRING_HASH[STRING_KEYS.sample]
end
def reading_frozen_hash
FROZEN_HASH[FROZEN_KEYS.sample]
end
Cùng xem kết quả:
Creating large Hash
Comparison:
Symbol Keys: 3243.5 i/s
Frozen Keys: 3022.1 i/s - 1.07x slower
String Keys: 2671.3 i/s - 1.21x slower
-----------------------------------------------------------------
Reading large Hash
Comparison:
Symbol Keys: 5930853.6 i/s
Frozen Keys: 5546042.9 i/s - 1.07x slower
String Keys: 5029193.7 i/s - 1.18x slower
Tổng kết
Như vậy các bạn có thể thấy sự khác biệt khá hớn với 1000 cặp key - value. Nếu bạn thực sự có những hash rất lớn, symbol key có thể giúp bạn cải thiện tốc độ ứng dụng. Nhưng theo tôi, bạn hãy tiếp dục dùng cách mà bạn đang dùng vì nếu string key khiến bạn code dễ dàng hơn, hãy tiếp tục dùng nó, bởi bạn có thể sẽ gặp nhiều vấn đề khi chuyển chúng sang symbol đó.
Tài liệu tham khảo: https://blog.gorbikoff.com/ruby-hashkey-showdown-symbol-vs-string/
All rights reserved