Question - Effective to change multiple values?
Fenny opened this issue · comments
This library is fast and awesome, the benchmarks speak for them self.
However, this is only for single value changes.
Is this library still effective compared with other serializers if you need to change multiple values?
And if so, could you provide an effective example?
sjson supports changing one element at a time.
Changing a few elements here and there will likely be very fast, but if you need to do a whole bunch of changes that alter the json significantly then you may want to investigate using the encoding/json
package to unmarshal/update/marshal.
To give you an idea, I whipped up this benchmark script, which takes a modest json payload and modifies out four values.
BenchmarkSJSON-16 402231 2946 ns/op
BenchmarkSJSONOptimistic-16 665307 1687 ns/op
BenchmarkGoMap-16 70814 15764 ns/op
BenchmarkGoStruct-16 144267 8116 ns/op
Thanks for providing a benchmark, when I replace encoding/json
with jsoniter
import "github.com/json-iterator/go"
var json = jsoniter.ConfigCompatibleWithStandardLibrary
I get the following results when changing 4 values
BenchmarkSJSONOptimistic-4 496299 2466 ns/op
BenchmarkJsoniterStruct-4 250891 4897 ns/op
And the following results when changing 7 values
BenchmarkSJSONOptimistic-4 192828 6084 ns/op
BenchmarkJsoniterStruct-4 247641 4953 ns/op
Can we conclude that Sjson cannot compete with other serializers when you have more than 4 operations?
Did you ever thought about a multiple value function for sjson?
sjson.Set(json string, values map[path]interface{})
Can we conclude that Sjson cannot compete with other serializers when you have more than 4 operations?
It really depends on the operations. If what you doing is replacing out many formally defined elements that exist in disparate locations, then a deserializer using struct tags is probably the way to go.
Sjson is a different beast with a different purpose. You can do stuff like targeting elements in json that do not have a formal structure, or composing json from nothing:
json, _ := sjson.Set("", "age", 21)
json, _ = sjson.Set(json, "name.first", "Tom")
json, _ = sjson.Set(json, "name.last", "Anderson")
// {"name":{"last":"Anderson","first":"Tom"},"age":21}
You can replace entire raw blocks, like objects or arrays using sjson.SetRaw()
:
json, _ = sjson.SetRaw(json, "name", `{"last":"Johnson","first":"Bill"}`)
// {"name":{"last":"Johnson","first":"Bill"},"age":21}
Or quickly rip out an element:
json, _ = sjson.Delete(json, "name")
// {"age":21}
I do my best to make each and every single operation as efficient as possible. But if you find a tool that works better for your use case, then by all means use that tool. There are so many json libraries that I can no longer keep track.
Did you ever thought about a multiple value function for sjson?
I've thought about it, but unfortunately, I have very little time to do the research.
@tidwall Thank you for your detailed comments 👍
I did some more benchmarks to see if we can squeeze more performance out of the benchmarks.
Benchmark_Set-4 3170313 341 ns/op 96 B/op 4 allocs/op
Benchmark_SetRaw-4 5310012 216 ns/op 80 B/op 3 allocs/op
Benchmark_SetBytes-4 4521404 258 ns/op 64 B/op 3 allocs/op
Benchmark_SetOptions-4 4863614 242 ns/op 80 B/op 3 allocs/op
Benchmark_SetRawBytes-4 5640955 188 ns/op 48 B/op 2 allocs/op
Benchmark_SetRawOptions-4 6496495 162 ns/op 64 B/op 2 allocs/op
Benchmark_SetBytesOptions-4 5707736 199 ns/op 48 B/op 2 allocs/op
Benchmark_SetRawBytesOptions-4 8263386 134 ns/op 32 B/op 1 allocs/op
SetRawBytesOptions
is by far the fastest if we are working with strings, SetBytesOptions
for other types.
Your package is currently the fastest way to serialize/edit small json operations, as you can see here: https://www.techempower.com/benchmarks/#section=test&runid=8721f3a4-7b13-4703-9cd8-91b6779668c2&hw=ph&test=json
easyjson still has better performance, but you need to pre-generate files.
I just want to say you did some great work with sjson 🏅