Ruby Hash[key] So sánh :symbol và “string”
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 ...
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).
Đầ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.
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
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 đó.