Skip to content
  • Jean Boussier's avatar
    8c7e69b7
    Optimize Hash#stringify_keys · 8c7e69b7
    Jean Boussier authored
    Using Symbol#name allows to hit two birds with one stone.
    
    First it will return a pre-existing string, so will save
    one allocation per key.
    
    Second, that string will be already interned, so it will
    save the internal `Hash` implementation the work of looking
    up the interned strings table to deduplicate the key.
    
    ```
    ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [x86_64-darwin21]
    Warming up --------------------------------------
                    to_s    17.768k i/100ms
                    cond    23.703k i/100ms
    Calculating -------------------------------------
                    to_s    169.830k (±10.4%) i/s -    852.864k in   5.088377s
                    cond    236.803k (± 7.9%) i/s -      1.185M in   5.040945s
    
    Comparison:
                    to_s:   169830.3 i/s
                    cond:   236803.4 i/s - 1.39x  faster
    ```
    
    ```ruby
    require 'bundler/inline'
    
    gemfile do
      source 'https://rubygems.org'
      gem 'benchmark-ips', require: false
    end
    
    HASH = {
      first_name: nil,
      last_name: nil,
      country: nil,
      profession: nil,
      language: nil,
      hobby: nil,
      pet: nil,
      longer_name: nil,
      occupation: nil,
      mailing_address: nil,
    }.freeze
    
    require 'benchmark/ips'
    
    Benchmark.ips do |x|
      x.report("to_s") { HASH.transform_keys(&:to_s) }
      x.report("cond") { HASH.transform_keys { |k| Symbol === k ? k.name : k.to_s } }
      x.compare!(order: :baseline)
    end
    ```
    8c7e69b7
    Optimize Hash#stringify_keys
    Jean Boussier authored
    Using Symbol#name allows to hit two birds with one stone.
    
    First it will return a pre-existing string, so will save
    one allocation per key.
    
    Second, that string will be already interned, so it will
    save the internal `Hash` implementation the work of looking
    up the interned strings table to deduplicate the key.
    
    ```
    ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [x86_64-darwin21]
    Warming up --------------------------------------
                    to_s    17.768k i/100ms
                    cond    23.703k i/100ms
    Calculating -------------------------------------
                    to_s    169.830k (±10.4%) i/s -    852.864k in   5.088377s
                    cond    236.803k (± 7.9%) i/s -      1.185M in   5.040945s
    
    Comparison:
                    to_s:   169830.3 i/s
                    cond:   236803.4 i/s - 1.39x  faster
    ```
    
    ```ruby
    require 'bundler/inline'
    
    gemfile do
      source 'https://rubygems.org'
      gem 'benchmark-ips', require: false
    end
    
    HASH = {
      first_name: nil,
      last_name: nil,
      country: nil,
      profession: nil,
      language: nil,
      hobby: nil,
      pet: nil,
      longer_name: nil,
      occupation: nil,
      mailing_address: nil,
    }.freeze
    
    require 'benchmark/ips'
    
    Benchmark.ips do |x|
      x.report("to_s") { HASH.transform_keys(&:to_s) }
      x.report("cond") { HASH.transform_keys { |k| Symbol === k ? k.name : k.to_s } }
      x.compare!(order: :baseline)
    end
    ```
Loading