Ruby Hash[key] Showdown :symbol vs “string”

Ruby Hash[key] Showdown :symbol vs “string”


Who cares?

There was recently a discussion on Trailblazer Gitter channel about Hashes as params, how to pass them around, and as customary a flame-war ~~ensued~~ never happened, and it came down to a measuring contest: ~~whose~~ which key is better and faster.

For the impatient: for small hashes it doesn’t really matter, for larger ones :symbol is upto 1.3x - 2x faster than string’ keys on really large Hashes. Frozen string’ keys are almost as fast as :symbol keys.

The best way to argue is to present facts. So I coded a couple of benchmarks and submitted a pull request to fast-ruby (Github). Here are the details.

Round 1: Hash[:symbol] vs Hash[“string”]

First, lets measure allocating Hash in various ways that Ruby gives us

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

Full code for the benchmark is here on Github and the results on rig with 8 cores and 16 GB of RAM, running on Ruby 2.4.2

Comparison:
        {symbol: 42}:  1731221.3 i/s
     {:symbol => 42}:  1714113.4 i/s - same-ish
     {'sym_str': 42}:  1711084.8 i/s - same-ish
    {"string" => 42}:  1508413.1 i/s - 1.15x  slower
    {'string' => 42}:  1452896.9 i/s - 1.19x  slower

So while 19% slower may be a fairly big difference, keep in mind that this is for 1.5 million iterations per second. Who in their right mind creates 1,500,000 single pair hashes per seconds? Right?

"string" keys are not going to be the speed bottleneck in your app.

Round 2: But what about large hashes?

Don’t worry I got you covered. You can check out specific benchmark right here on Github. Let's try it out for a 1000 key-value pairs.

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

Full benchmark code . Let’s see the results:

Creating large Hash

Comparison:
         Symbol Keys:     3262.0 i/s
         Frozen Keys:     3023.2 i/s - same-ish
         String Keys:     2476.7 i/s - 1.32x  slower

Reading large Hash

Comparison:
         Symbol Keys:  5280882.7 i/s
         Frozen Keys:  4791128.0 i/s - same-ish
         String Keys:  4275730.5 i/s - 1.24x  slower

So as we can see on a larger Hashes with 1000’s of keys, the difference becomes more apparent and being mindful of it can help improve speed, if you are using a lot of large hashes. Otherwise, my recommendation, keep using what works better for you app. If string keys make it easier, let’s say you are importing them from an external file, don’t go through the trouble of converting them to symbols, it’s probably not worth it.

But don’t take my word for it. Just measure it.

#SoftwareEngineering #Programming #Ruby #Benchmarks #Performance #RubyOnRails #Rails

Originally published at History Bits.

IMHO, I'd go with symbols from the start. If you start with strings but later decide that you'd like to get that 20% speed up, then you have the potential of having to modify a significant amount of code. If you do this towards the end of a deadline, you might have other pressing problems to deal with or it might seem too risky to change at such a late date.

回复

要查看或添加评论,请登录

Nick Gorbikoff ???? ?? ??的更多文章

  • Lucky is lightning fast!

    Lucky is lightning fast!

    TechEmpower just posted Round #20 of their Web Framework benchmarks and Lucky Framework (that runs on Crystal Language)…

    1 条评论
  • Fuchsia OS - Google's new operating system

    Fuchsia OS - Google's new operating system

    Details are still sparse about #Fuchsia #Google's new OS, and in the coming months we will find out more but as of…

    1 条评论
  • Why do people like Elixir?

    Why do people like Elixir?

    What is there not to like? I recently started learning Elixir, and so far I haven’t found any downsides. It’s…

    8 条评论

社区洞察

其他会员也浏览了