Skip to content

Instantly share code, notes, and snippets.

@barbolo
Last active September 24, 2022 03:32
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save barbolo/0a2bf9e78d9484fca1efe4ea4a9c0f31 to your computer and use it in GitHub Desktop.
Save barbolo/0a2bf9e78d9484fca1efe4ea4a9c0f31 to your computer and use it in GitHub Desktop.
Benchmark of JSON rendering in Ruby
# gem install multi_json json yajl-ruby oj benchmark-memory
require 'multi_json'
require 'json'
require 'yajl'
require 'oj'
require 'benchmark'
require 'benchmark-memory'
hash1 = {
'key1' => 'string', # String
'key2' => 153, # Integer
'key3' => 224.81, # Float
'key4' => true, # Boolean
'key5' => nil, # Null
'key6' => Date.today, # Date
'key7' => Time.now, # Datetime
}
hash2 = hash1.merge({
'key8' => { # 3-level tree
'key8.1' => hash1.clone,
'key8.2' => {
'key8.2.1' => hash1.clone,
'key8.2.2' => hash1.clone
}
},
'key9' => 10.times.map { hash1.clone }, # Array of Hashes
'key10' => 'a'*100_000, # 100KB file
})
hash3 = Hash[1_000.times.map do |i|
key = "key#{i+1}"
value = if i % 2 == 0
hash1.clone
else
[hash1.clone, {'1' => {'2' => {'3' => {'4' => {'5' => {'6' => {'7' => hash2.clone}}}}}}}]
end
[key, value]
end]
[hash1, hash2, hash3].each_with_index do |hash_i, i|
puts
puts '------------------'
puts "Benchmark of hash#{i+1}"
puts '------------------'
nrep = 100
bench = Benchmark.bm(10) do |x|
MultiJson.use :json_gem
x.report('json_gem:') { nrep.times { MultiJson.dump(hash_i) } }
MultiJson.use :yajl
x.report('yajl:') { nrep.times { MultiJson.dump(hash_i) } }
MultiJson.use :oj
x.report('oj:') { nrep.times { MultiJson.dump(hash_i) } }
x.report('to_json:') { nrep.times { hash_i.to_json } }
end
puts
puts "Results in ms per execution:"
bench.each do |bm|
puts ">>>>> #{bm.label} - %.3f ms" % (bm.real*1000.0/nrep)
end
puts
# https://github.com/michaelherold/benchmark-memory
Benchmark.memory do |x|
MultiJson.use :json_gem
x.report('json_gem:') { MultiJson.dump(hash_i) }
MultiJson.use :yajl
x.report('yajl:') { MultiJson.dump(hash_i) }
MultiJson.use :oj
x.report('oj:') { MultiJson.dump(hash_i) }
x.report('to_json:') { hash_i.to_json }
x.compare!
end
end
# gem install multi_json oj benchmark-memory rabl jbuilder
require 'multi_json'
require 'oj'
require 'rabl'
require 'jbuilder'
require 'benchmark'
require 'benchmark-memory'
class BaseModel
def initialize(attrs={})
attrs.each { |k, v| self.send("#{k}=", v) }
end
end
class UserModel < BaseModel
attr_accessor :name, :age, :email
end
class CommentModel < BaseModel
attr_accessor :user, :message, :created_at, :attachment
end
class PostModel < BaseModel
attr_accessor :content, :author, :comments, :created_at, :published
end
def create_post(size=1_000, comments=10, attachment_size=0)
PostModel.new(
content: '-'*size,
author: UserModel.new(name: 'First Last', age: rand(100), email: 'user@email.com'),
created_at: Time.now,
published: true,
comments: comments.times.map do
CommentModel.new(
user: UserModel.new(name: 'First Last', age: rand(100), email: 'user@email.com'),
message: '-'*400,
created_at: Time.now,
attachment: '-'*attachment_size
)
end
)
end
def render_jbuilder(post)
Jbuilder.encode do |json|
json.content post.content
json.created_at post.created_at
json.published post.published
json.author do
json.name post.author.name
json.age post.author.age
json.email post.author.email
end
json.comments post.comments do |comment|
json.created_at comment.created_at
json.message comment.message
json.user do
json.name comment.user.name
json.age comment.user.age
json.email comment.user.email
end
json.attachment comment.attachment
end
end
end
def render_rabl(post)
# # Create a post.rabl file with the following content
# attribute :content
# attribute :created_at
# attribute :published
# child(:author) do
# attribute :name
# attribute :age
# attribute :email
# end
# child(:comments) do
# attribute :created_at
# attribute :message
# child(:user) do
# attribute :name
# attribute :age
# attribute :email
# end
# attribute :attachment
# end
Rabl.render(post, 'post', view_path: '.', format: :json)
end
def render_dump(post)
MultiJson.dump({
'content' => post.content,
'created_at' => post.created_at,
'published' => post.published,
'author' => {
'name' => post.author.name,
'age' => post.author.age,
'email' => post.author.email,
},
'comments' => post.comments.map do |comment|
{
'created_at' => comment.created_at,
'message' => comment.message,
'user' => {
'name' => comment.user.name,
'age' => comment.user.age,
'email' => comment.user.email,
},
'attachment' => comment.attachment,
}
end
})
end
def render_string(post)
%({
"content": #{MultiJson.encode(post.content)},
"created_at": #{MultiJson.encode(post.created_at)},
"published": #{MultiJson.encode(post.published)},
"author":{
"name": #{MultiJson.encode(post.author.name)},
"age": #{MultiJson.encode(post.author.age)},
"email": #{MultiJson.encode(post.author.email)}
},
"comments":[
#{
post.comments.map do |comment|
%({
"created_at": #{MultiJson.encode(comment.created_at)},
"message": #{MultiJson.encode(comment.message)},
"user":{
"name": #{MultiJson.encode(comment.user.name)},
"age": #{MultiJson.encode(comment.user.age)},
"email": #{MultiJson.encode(comment.user.email)}
},
"attachment": #{MultiJson.encode(comment.attachment)}
})
end.join(",\n")
}
]
})
end
# Confirm render_string is working fine
# MultiJson.load(render_string(post_i)) == MultiJson.load(render_dump(post_i))
post1 = create_post(1_000, 10, 0)
post2 = create_post(1_000_000, 200, 1_000)
post3 = create_post(10_000_000, 5_000, 10_000)
MultiJson.use :oj
[post1, post2, post3].each_with_index do |post_i, i|
puts
puts '------------------'
puts "Benchmark of post#{i+1}"
puts '------------------'
nrep = 1000
bench = Benchmark.bm(10) do |x|
x.report('rabl:') { nrep.times { render_rabl(post_i) } }
x.report('jbuilder:') { nrep.times { render_jbuilder(post_i) } }
x.report('dump:') { nrep.times { render_dump(post_i) } }
x.report('string:') { nrep.times { render_string(post_i) } }
end
puts
puts "Results in ms per execution:"
bench.each do |bm|
puts ">>>>> #{bm.label} - %.3f ms" % (bm.real*1000.0/nrep)
end
puts
# https://github.com/michaelherold/benchmark-memory
Benchmark.memory do |x|
x.report('rabl:') { render_rabl(post_i) }
x.report('jbuilder:') { render_jbuilder(post_i) }
x.report('dump:') { render_dump(post_i) }
x.report('string:') { render_string(post_i) }
x.compare!
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment