Coder Social home page Coder Social logo

Comments (12)

yanfali avatar yanfali commented on May 23, 2024 1

@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.

yanfali avatar yanfali commented on May 23, 2024

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.

smyrman avatar smyrman commented on May 23, 2024

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.

smyrman avatar smyrman commented on May 23, 2024

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.

yanfali avatar yanfali commented on May 23, 2024

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.

smyrman avatar smyrman commented on May 23, 2024

Yes, I agree to that @yanfali. The performance of JSON Schema generation probably hardly matters to anyone.

from rest-layer.

smyrman avatar smyrman commented on May 23, 2024

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.

smyrman avatar smyrman commented on May 23, 2024

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.

yanfali avatar yanfali commented on May 23, 2024

from rest-layer.

smyrman avatar smyrman commented on May 23, 2024

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.

rs avatar rs commented on May 23, 2024

Can we close this issue now?

from rest-layer.

smyrman avatar smyrman commented on May 23, 2024

Yes

from rest-layer.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.