Skip to content

Instantly share code, notes, and snippets.

@indirect
Forked from koffeinfrei/.ruby-version
Last active February 25, 2023 23:01
Show Gist options
  • Save indirect/d6354b39b58a0c65a3a61e34f16c91dc to your computer and use it in GitHub Desktop.
Save indirect/d6354b39b58a0c65a3a61e34f16c91dc to your computer and use it in GitHub Desktop.
Performance comparison of different ruby serializer methods
require './serializer_benchmarks'
hash = {
'name' => 'Fredrick Smith',
'quantity' => 1_000_000,
'addresses' => {
'address1' => '12 Heather Street, Parnell, Auckland, New Zealand',
'address2' => '1 Queen Street, CBD, Auckland, New Zealand'
}
}
run(hash)
run('string')
run(3.4)
run(nil)
run(true)
source 'https://rubygems.org'
gem 'benchmark-ips', require: 'benchmark/ips'
gem 'bson'
gem 'json'
gem 'msgpack'
gem 'oj'
gem 'yajl-ruby'
gem 'json_pure'
gem "rufo", "~> 0.15.1"
GEM
remote: https://rubygems.org/
specs:
benchmark-ips (2.7.2)
bson (4.3.0)
json (2.1.0)
json_pure (2.6.3)
msgpack (1.2.4)
oj (3.5.0)
rufo (0.15.1)
yajl-ruby (1.3.1)
PLATFORMS
ruby
DEPENDENCIES
benchmark-ips
bson
json
json_pure
msgpack
oj
rufo (~> 0.15.1)
yajl-ruby
BUNDLED WITH
2.4.7
require './serializer_benchmarks'
hash = {
'name' => 'Fredrick Smith',
'quantity' => 1_000_000,
'addresses' => {
'address1' => '12 Heather Street, Parnell, Auckland, New Zealand',
'address2' => '1 Queen Street, CBD, Auckland, New Zealand'
}
}
class CustomClass
attr_accessor :variable
def run(a, b)
a + b
end
def ==(other_custom_class)
self.variable == other_custom_class.variable
end
end
custom_class = CustomClass.new.tap { |instance| instance.variable = 'value' }
benches = DEFAULT_BENCHES.slice(:marshal, :json)
# run(custom_class, benches)
run(hash, benches)
# run(custom_class, benches)
# run('string', benches)
# run(3.4, benches)
# run(3, benches)
# run(nil, benches)
# run(true, benches)
# Intel(R) Core(TM) i7-7600U CPU @ 2.80GHz, 16GB DDR3 RAM
# ruby 2.5.0
# all_with_hash.rb
--> Benchmarking an object of type Hash
JSON (using oj): 68.3 i/s
MessagePack: 62.7 i/s - 1.09x slower
BSON: 54.7 i/s - 1.25x slower
Marshal: 41.4 i/s - 1.65x slower
JSON (using Yajl): 31.3 i/s - 2.18x slower
JSON (built-in ruby): 26.9 i/s - 2.54x slower
YAML: 1.2 i/s - 59.15x slower
--> Benchmarking an object of type String
JSON (using oj): 344.6 i/s
BSON: 308.3 i/s - 1.12x slower
Marshal: 151.1 i/s - 2.28x slower
MessagePack: 127.8 i/s - 2.70x slower
JSON (built-in ruby): 99.2 i/s - 3.47x slower
JSON (using Yajl): 96.9 i/s - 3.55x slower
YAML: 4.7 i/s - 74.01x slower
--> Benchmarking an object of type Float
BSON: 332.6 i/s
JSON (using oj): 204.1 i/s - 1.63x slower
Marshal: 168.1 i/s - 1.98x slower
MessagePack: 124.3 i/s - 2.68x slower
JSON (built-in ruby): 83.8 i/s - 3.97x slower
JSON (using Yajl): 80.2 i/s - 4.15x slower
YAML: 4.5 i/s - 73.27x slower
# reduced_with_different_objects.rb
--> Benchmarking an object of type Float
JSON (using oj): 198.8 i/s
Marshal: 169.1 i/s - 1.18x slower
--> Benchmarking an object of type Hash
JSON (using oj): 70.9 i/s
Marshal: 44.4 i/s - 1.60x slower
--> Benchmarking an object of type String
JSON (using oj): 368.0 i/s
Marshal: 158.3 i/s - 2.33x slower
--> Benchmarking an object of type CustomClass
JSON (using oj): 195.2 i/s
Marshal: 87.4 i/s - 2.23x slower
require 'benchmark/ips'
require 'bson'
require 'json'
require 'msgpack'
require 'oj'
require 'yajl'
require 'yaml'
require 'json/pure'
SAMPLES = 5_000
DEFAULT_BENCHES = {
marshal: 'Marshal',
json: 'JSON (built-in ruby)',
yajl: 'JSON (using Yajl)',
oj: 'JSON (using oj)',
bson: 'BSON',
yaml: 'YAML',
msgpack: 'MessagePack'
}.freeze
def encode(msg, format)
case format
when :yaml
msg.to_yaml
when :marshal
Marshal.dump(msg)
when :json
JSON.generate(msg)
when :yajl
Yajl::Encoder.encode(msg)
when :oj
Oj.dump(msg)
when :bson
msg.to_bson
when :msgpack
MessagePack.pack(msg)
end
end
def decode(str, format, type)
case format
when :yaml
YAML.load(str)
when :marshal
Marshal.load(str)
when :json
JSON.parse(str)
when :yajl
Yajl::Parser.parse(str)
when :oj
Oj.load(str)
when :bson
type.from_bson(str)
when :msgpack
MessagePack.unpack(str)
end
end
def run(obj, benches = DEFAULT_BENCHES)
puts "--> Benchmarking an object of type #{obj.class}"
Benchmark.ips do |r|
benches.each do |key, title|
r.report(title) do
SAMPLES.times do
decoded_obj = decode(encode(obj, key), key, obj.class)
if decoded_obj != obj
raise <<~RAISE
Deserialized object of type #{obj.class} is not the same as before serialization / deserialization
before: #{obj.inspect}
after: #{decoded_obj.inspect}
RAISE
end
end
end
end
r.compare!
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment