Skip to content

Instantly share code, notes, and snippets.

@fnordfish
Created December 5, 2018 10:21
Show Gist options
  • Save fnordfish/a8733c8aed8efea05934aaffc853601c to your computer and use it in GitHub Desktop.
Save fnordfish/a8733c8aed8efea05934aaffc853601c to your computer and use it in GitHub Desktop.
Micro-benchmarking different error handling methods in ruby
# frozen_string_literal: true
# Some, probable not extreamly clever, micro benchmarks to compare
# different methods of "return a value or error".
# The samples benchmark the error path only.
require 'benchmark/ips'
require 'dry/monads/result'
M = Dry::Monads
Result = Struct.new(:success, :value)
def _return_nil; nil end
def _return_failure; M.Failure("error") end
def _return_struct; Result.new(false, "error") end
def _raise_error; raise StandardError, "error" end
def _throw_error; throw(:test, "error") end
def fastest
result = _return_nil
result if result
end
def medium
result = catch(:test) { _throw_error }
result
end
def slow
result = begin
_raise_error
rescue StandardError => e
nil
end
result
end
def dry_failure
result = _return_failure
result.value_or(nil)
end
def result_struct
result = _return_struct
result.success ? result.value : nil
end
Benchmark.ips do |x|
x.warmup = 100
x.report('return') { fastest }
x.report('throw') { medium }
x.report('raise') { slow }
x.report('Failure()') { dry_failure }
x.report('Struct') { result_struct }
x.compare!
end
###
# macOS 10.14.1
# Intel(R) Core(TM) i7-4980HQ CPU @ 2.80GHz
# 16GB RAM
# Lots of background noise
###
#
# ruby 2.6.0preview3 (2018-11-06 trunk 65578) [x86_64-darwin18]
# raise_vs_return.rb:28: warning: assigned but unused variable - e
# Calculating -------------------------------------
# return 207.114k i/100ms
# throw 143.958k i/100ms
# raise 74.611k i/100ms
# Failure() 38.082k i/100ms
# Struct 149.491k i/100ms
# -------------------------------------------------
# return 14.433M (± 4.2%) i/s - 72.076M
# throw 3.772M (± 3.1%) i/s - 18.858M
# raise 1.121M (± 4.7%) i/s - 5.596M
# Failure() 472.264k (± 3.4%) i/s - 2.361M
# Struct 4.539M (± 3.2%) i/s - 22.723M
#
# Comparison:
# return: 14433477.6 i/s
# Struct: 4538907.4 i/s - 3.18x slower
# throw: 3771951.7 i/s - 3.83x slower
# raise: 1120595.5 i/s - 12.88x slower
# Failure(): 472264.2 i/s - 30.56x slower
#
###
#
# ruby --jit -v raise_vs_return.rb
# ruby 2.6.0preview3 (2018-11-06 trunk 65578) +JIT [x86_64-darwin18]
# raise_vs_return.rb:28: warning: assigned but unused variable - e
# Calculating -------------------------------------
# return 224.228k i/100ms
# throw 148.997k i/100ms
# raise 75.438k i/100ms
# Failure() 38.648k i/100ms
# Struct 164.680k i/100ms
# -------------------------------------------------
# return 24.915M (± 4.6%) i/s - 124.222M
# throw 3.983M (± 6.3%) i/s - 19.817M
# raise 1.139M (± 3.0%) i/s - 5.733M
# Failure() 485.783k (± 6.4%) i/s - 2.435M
# Struct 5.195M (± 6.0%) i/s - 25.855M
#
# Comparison:
# return: 24914915.7 i/s
# Struct: 5194806.9 i/s - 4.80x slower
# throw: 3982539.1 i/s - 6.26x slower
# raise: 1139278.3 i/s - 21.87x slower
# Failure(): 485783.5 i/s - 51.29x slower
#
###
#
# jruby 9.2.4.1 (2.5.0) 2018-11-28 f487d1e Java HotSpot(TM) 64-Bit Server VM 25.60-b23 on 1.8.0_60-b27 +jit [darwin-x86_64]
# Calculating -------------------------------------
# return 148.276k i/100ms
# throw 52.078k i/100ms
# raise 1.389k i/100ms
# Failure() 1.294k i/100ms
# Struct 113.227k i/100ms
# -------------------------------------------------
# return 18.470M (± 7.6%) i/s - 91.486M
# throw 917.148k (± 2.9%) i/s - 4.583M
# raise 14.407k (± 3.6%) i/s - 72.228k
# Failure() 13.793k (± 2.1%) i/s - 69.876k
# Struct 6.767M (± 4.0%) i/s - 33.742M
#
# Comparison:
# return: 18469948.6 i/s
# Struct: 6767455.3 i/s - 2.73x slower
# throw: 917147.5 i/s - 20.14x slower
# raise: 14407.3 i/s - 1281.99x slower
# Failure(): 13793.2 i/s - 1339.06x slower#
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment