I went ahead and did a benchmark with 4 structs using JSON::Serializable
, each with some primitive data types and a nested object.
require "benchmark"
require "json"
struct CorsObject
include JSON::Serializable
getter str : String
getter int : Int32
getter int_64 : Int64
getter float : Float64
getter bool : Bool
end
struct CorsConfig
include JSON::Serializable
getter cors_object : CorsObject
getter str : String
getter int : Int32
getter int_64 : Int64
getter float : Float64
getter bool : Bool
end
struct RouteConfig
include JSON::Serializable
getter cors : CorsConfig
getter str : String
getter int : Int32
getter int_64 : Int64
getter float : Float64
getter bool : Bool
end
struct Config
include JSON::Serializable
getter routing : RouteConfig
getter str : String
getter int : Int32
getter int_64 : Int64
getter float : Float64
getter bool : Bool
end
json_str = <<-JSON
{
"str": "config_string",
"int": 1,
"int_64": 111,
"float": 1.11,
"bool": true,
"routing": {
"str": "routing_string",
"int": 2,
"int_64": 222,
"float": 2.22,
"bool": false,
"cors": {
"str": "cors_string",
"int": 3,
"int_64": 3,
"float": 3.33,
"bool": false,
"cors_object": {
"str": "cors_object_string",
"int": 4,
"int_64": 444,
"float": 4.44,
"bool": true
}
}
}
}
JSON
json_config = Config.from_json json_str
json_parse_config = JSON.parse json_str
puts "Just parsing the structure"
Benchmark.ips do |x|
x.report("from_json") do
Config.from_json json_str
end
x.report("JSON.parse") do
JSON.parse json_str
end
end
puts
puts "Parse the structure and read a nested value"
Benchmark.ips do |x|
x.report("from_json") do
config = Config.from_json json_str
config.routing.cors.float
end
x.report("JSON.parse") do
config = JSON.parse json_str
config["routing"]["cors"]["float"].as_f
end
end
puts
puts "Just access already parsed data"
Benchmark.ips do |x|
x.report("from_json") do
json_config.routing.cors.float
end
x.report("JSON.parse") do
json_parse_config["routing"]["cors"]["float"].as_f
end
end
The results
Just parsing the structure
from_json 309.73k ( 3.23µs) (± 2.96%) 1728 B/op fastest
JSON.parse 264.19k ( 3.79µs) (± 2.65%) 3697 B/op 1.17× slowerParse the structure and read a nested value
from_json 306.01k ( 3.27µs) (± 4.53%) 1728 B/op fastest
JSON.parse 259.74k ( 3.85µs) (± 2.80%) 3697 B/op 1.18× slowerJust access already parsed data
from_json 884.2M ( 1.13ns) (± 2.47%) 0 B/op fastest
JSON.parse 23.16M ( 43.17ns) (± 1.96%) 0 B/op 38.17× slower
So from this, what can we tell?
from_json
is slightly faster in parsing the string into an object.from_json
is slightly faster in parsing the string, then reading a value from itfrom_json
is substantially faster in reading values after the initial parsing.
In conclusion, from_json
is faster in every way. JSON.parse
comes close in initial parsing of the string, probably due to them both using similar parsing methods. However, once the string is parsed into an object, in this case structs, reading values from it is much faster.