sjson icon indicating copy to clipboard operation
sjson copied to clipboard

Question - Effective to change multiple values?

Open Fenny opened this issue 4 years ago • 4 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?

Fenny avatar Jan 29 '20 18:01 Fenny

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

tidwall avatar Jan 29 '20 20:01 tidwall

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{})

Fenny avatar Jan 30 '20 18:01 Fenny

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 avatar Jan 30 '20 19:01 tidwall

@tidwall Thank you for your detailed comments :+1: 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 :medal_sports:

Fenny avatar Jan 30 '20 20:01 Fenny