Comments (12)
@smyrman I agree with the benchmarks though. I would like to know how much slower it is than a hand coded version.
from rest-layer.
I think this is worth attempting. I just took a look at https://golang.org/src/encoding/json/encode.go and it's pretty much switch statements and writing to buffers, but if you can make the code less error prone that's a worth goal. Writing serializers and deserializers tends to be a low level and messy business.
from rest-layer.
and it's pretty much switch statements and writing to buffers
Yeah, but they also have a separate type for each encoder (intEncoder, uintEncoder etc.). See https://golang.org/src/encoding/json/encode.go#L391.
Writing serializers and deserializers tends to be a low level and messy business.
I have actually written a binary one, and yes I agree. The biggest question is which solution to go with... I have three (new) proposals that I have added to #35, as I am thinking about using the same interface externally (public) as we use internally. Each solution have some advantages and disadvantages.
from rest-layer.
FYI, I now have a working plan on this, which involves 3 steps.
First of all, I will create some micro-benchmarks for the jsonschema
package, and add this as a separate PR.
Secondly, I will clean up the code by splitting the encoder into separate files with one encoder per supported type, mirroring the layout of the schema package. The encoder logic itself will be more or less exactly the same as it is now, except the encoder-logic for each type will move into a separate function. This will be the second PR. Most likely, I will pass in an io.Writer rather than an errWriter to each encoder.
Thirdly, I really want to try out solution 2 from #35, which involves getting rid of all the JSON encoder logic altogether, and simply deal with map[string]interface{}
internally, and only use the standard-library JSON encoder. This would be in line with how API payloads are serialized/deserialized. From the discussion in #35, this proposal does not necessarily have any buy-in yet, so this PR might be rejected. However, if writing serializers and deserializers are messy and low level, surely avoiding it altogether would make for a more robust, although worse performing, solution. Dealing with maps, also holds the door open for end-users to implement other encodings (e.g. YAML) to be used for JSON Schema / Swagger, similar to how the rest
package today allows for a custom ResponseSender
.
from rest-layer.
One thought I have about the performance is that it would be fairly easy to memoize the output after a single run so we trade memory for speed and amortize the cost. Right now these things run fairly infrequently for me and are mostly informational so the performance isn't a huge concern.
from rest-layer.
Yes, I agree to that @yanfali. The performance of JSON Schema generation probably hardly matters to anyone.
from rest-layer.
I guess that really means that the micro benchmarks (step 1), aren't really going to be necessary. I will write some anyway, as I am quite interested in seeing the difference in performance / number of allocations between the two approaches on a general basis, even though encoding performance isn't critical here.
UPDATE: I can submit a PR for them, but I am happy if we decide to reject them.
from rest-layer.
OK, the code for a map[string]interface{}
based encoding in JSONSchema is ready, and so are the benchmark results. I will wait with the PR unitl #70 is merged, but you may pre-inspect the code here.
I think the code is really much cleaner, but a bit slower, especially for tiny schemas. Compared to #70, here are the benchmark results from my machine:
benchmark old ns/op new ns/op delta
BenchmarkEncoder/Schema={Fields:{"b":Bool{}}} 1318 5405 +310.09%
BenchmarkEncoder/Schema={Fields:{"s":String{}}} 1249 5270 +321.94%
BenchmarkEncoder/Schema={Fields:{"s":String{MaxLen:42}}} 1550 6063 +291.16%
BenchmarkEncoder/Schema=Student 9797 20723 +111.52%
benchmark old allocs new allocs delta
BenchmarkEncoder/Schema={Fields:{"b":Bool{}}} 14 40 +185.71%
BenchmarkEncoder/Schema={Fields:{"s":String{}}} 14 40 +185.71%
BenchmarkEncoder/Schema={Fields:{"s":String{MaxLen:42}}} 16 44 +175.00%
BenchmarkEncoder/Schema=Student 59 136 +130.51%
benchmark old bytes new bytes delta
BenchmarkEncoder/Schema={Fields:{"b":Bool{}}} 496 2225 +348.59%
BenchmarkEncoder/Schema={Fields:{"s":String{}}} 480 2225 +363.54%
BenchmarkEncoder/Schema={Fields:{"s":String{MaxLen:42}}} 504 2344 +365.08%
BenchmarkEncoder/Schema=Student 2528 7033 +178.20%
Machine details:
Hardware Overview:
Model Name: MacBook Pro
Model Identifier: MacBookPro11,1
Processor Name: Intel Core i5
Processor Speed: 2.6 GHz
Number of Processors: 1
Total Number of Cores: 2
L2 Cache (per Core): 256 KB
L3 Cache: 3 MB
Memory: 8 GB
Commands to reproduce:
$ git checkout ... # old code
$ go test -run=NONE -bench=. -benchmem -cpu 1 > 1.txt
$ git checkout ... # new code
$ go test -run=NONE -bench=. -benchmem -cpu 1 > 2.txt
$ benchcmp 1.txt 2.txt
from rest-layer.
from rest-layer.
The most representable one atm. is probably the "Schema=Student" test, which is a small schema, but not a tiny one. It is a bit more than twice as slow with ~20ms v.s. ~10ms before. The tiny examples are more than 4x slower. If I were to guess, I would say there is probably a 3ms added overhead with this solution and a ~2x slowdown.
I think for the case of API documentation, this is acceptable. But if it was for the main payload transferred by the API, it probably would not be.
How about an array containing an object containing an array containing a different object. Each object should have at least 6 fields.
Yeah, you can do so if you like. I don't know how much the nesting matters, as also fields get their own maps, so I am guessing it might perform similar to a flat schema with 10+ fields. Probably a bit slower since the map allocated for a Schema is larger than the one allocated for fields.
from rest-layer.
Can we close this issue now?
from rest-layer.
Yes
from rest-layer.
Related Issues (20)
- Remove old sub-resource syntax HOT 4
- go module: cannot find module providing package testing/mem HOT 3
- Explicit $eq in filter passes whole predicate to Validate(Query) HOT 3
- OnInsert/OnUpdate hooks can modify the new resource item, Etag not recalculated HOT 7
- `Prefer: return=minimal` can hide resource item on server modification HOT 12
- Consistent empty / null fields HOT 4
- Remove resource hooks in favor of resource middleware HOT 12
- Newest `zerolog` versions cause a panic HOT 4
- Bogus error line, when returning empty response on 204
- Etag should not depend on external state HOT 4
- Assist AutoIncrement FieldValidator with SQL backend HOT 8
- How use schema and resource package as standalone HOT 1
- Bulk PATCH support HOT 5
- Wrapping original issue in rest.Error HOT 7
- Feature Request: Cursor-based Pagination HOT 3
- pq: operator does not exist: uuid ~~ unknown HOT 7
- Filter on reference fields HOT 1
- Support for $not filter operation HOT 4
- Decouple ElemMatch from schema.Array struct
- openapi 3.1.0 support HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from rest-layer.