Skip to content

Instantly share code, notes, and snippets.

@le0pard
Created September 10, 2021 12:15
Show Gist options
  • Save le0pard/cb6b5e3a1f63a5337d2a2ae74115f3c6 to your computer and use it in GitHub Desktop.
Save le0pard/cb6b5e3a1f63a5337d2a2ae74115f3c6 to your computer and use it in GitHub Desktop.
OpenStruct vs Struct vs Hash in Ruby
require 'benchmark/ips'
require 'ostruct'
# Enable and start GC before each job run. Disable GC afterwards.
class GCSuite
def warming(*)
run_gc
end
def running(*)
run_gc
end
def warmup_stats(*)
end
def add_report(*)
end
private
def run_gc
GC.enable
GC.start
GC.disable
end
end
suite = GCSuite.new
data = { x: 100, y: 200 }
PointStruct = Struct.new(:x, :y)
class FakedPointStruct
attr_accessor :x, :y
def initialize(x, y)
@x = x
@y = y
end
end
class PointClass
attr_accessor :x, :y
def initialize(args)
@x = args.fetch(:x) # NOTE: Hash#fetch -> performance impact
@y = args.fetch(:y)
end
end
puts "\n\nINITIALIZATION =========="
Benchmark.ips do |x|
x.config(suite: suite)
# Create Objects as a reference value
x.report("Object.new") { Object.new }
x.report("FakedPointStruct") { FakedPointStruct.new(100, 200) }
x.report("PointStruct") { PointStruct.new(100, 200) }
x.report("Hash[]") { Hash[data] }
x.report("PointClass") { PointClass.new(data) }
x.report("Hash#merge") { Hash.new.merge(data) }
x.report("OpenStruct") { OpenStruct.new(data) }
end
puts "\n\nREAD =========="
point_struct = PointStruct.new(100, 200)
point_class = PointClass.new(data)
point_hash = Hash[data]
point_open_struct = OpenStruct.new(data)
Benchmark.ips do |x|
x.config(suite: suite)
x.report("PointStruct") { point_struct.x }
x.report("PointClass") { point_class.x }
x.report("Hash#fetch") { point_hash.fetch(:x) }
x.report("Hash#[]") { point_hash[:x] }
x.report("OpenStruct") { point_open_struct.x }
end
puts "\n\nWRITE =========="
Benchmark.ips do |x|
x.config(suite: suite)
x.report("PointStruct") { point_struct.x = 1 }
x.report("PointClass") { point_class.x = 1 }
x.report("Hash") { point_hash[:x] = 1 }
x.report("OpenStruct") { point_open_struct.x = 1 }
end
# INITIALIZATION ==========
# Warming up --------------------------------------
# Object.new 577.732k i/100ms
# FakedPointStruct 464.942k i/100ms
# PointStruct 488.484k i/100ms
# Hash[] 387.569k i/100ms
# PointClass 347.606k i/100ms
# Hash#merge 227.653k i/100ms
# OpenStruct 151.441k i/100ms
# Calculating -------------------------------------
# Object.new 5.297M (±15.1%) i/s - 25.998M in 5.036946s
# FakedPointStruct 4.210M (± 9.2%) i/s - 21.387M in 5.124131s
# PointStruct 4.351M (±11.8%) i/s - 21.493M in 5.024872s
# Hash[] 3.412M (±20.6%) i/s - 16.665M in 5.080603s
# PointClass 3.184M (± 8.0%) i/s - 15.990M in 5.058015s
# Hash#merge 2.149M (±17.2%) i/s - 10.472M in 5.007291s
# OpenStruct 1.496M (± 6.1%) i/s - 7.572M in 5.078252s
# READ ==========
# Warming up --------------------------------------
# PointStruct 1.520M i/100ms
# PointClass 1.798M i/100ms
# Hash#fetch 1.232M i/100ms
# Hash#[] 1.393M i/100ms
# OpenStruct 646.764k i/100ms
# Calculating -------------------------------------
# PointStruct 13.659M (±11.9%) i/s - 68.401M in 5.103649s
# PointClass 16.637M (± 6.1%) i/s - 84.504M in 5.100355s
# Hash#fetch 12.108M (± 6.4%) i/s - 60.387M in 5.013311s
# Hash#[] 16.935M (± 2.2%) i/s - 84.955M in 5.019082s
# OpenStruct 7.410M (±13.4%) i/s - 36.219M in 5.012097s
# WRITE ==========
# Warming up --------------------------------------
# PointStruct 1.090M i/100ms
# PointClass 1.493M i/100ms
# Hash 1.296M i/100ms
# OpenStruct 520.228k i/100ms
# Calculating -------------------------------------
# PointStruct 11.665M (±12.3%) i/s - 57.782M in 5.082646s
# PointClass 16.112M (± 3.3%) i/s - 80.636M in 5.010430s
# Hash 11.975M (±12.1%) i/s - 59.606M in 5.095005s
# OpenStruct 4.495M (±14.8%) i/s - 22.370M in 5.127749s
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment