Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deserializing in real time, mutable objects #54

Closed
emmx opened this issue May 31, 2018 · 3 comments
Closed

Deserializing in real time, mutable objects #54

emmx opened this issue May 31, 2018 · 3 comments

Comments

@emmx
Copy link

emmx commented May 31, 2018

I'm deserializing an array of objects as follows:

// This is cached, only one instance created
DslJson<Object> dslJson = new DslJson<>(Settings.withRuntime().includeServiceLoader());
JsonReader reader = dslJson.newReader();

// I run this part in a loop thousands of times per second
HttpResponse<InputStream> httpResponse = request.asBinary();
reader.process(httpResponse.getBody());
if (reader.getNextToken() == '[') {
    do {
        // Read beginning of object
        reader.getNextToken(); // {

        // Read id
        reader.getNextToken(); // "
        reader.fillName();     // id
        reader.getNextToken(); // "
        String id = reader.readString(); // foo
        reader.getNextToken(); // ,

        // Read price
        reader.getNextToken(); // "
        reader.fillName();     // price
        reader.getNextToken(); // "
        double price = NumberConverter.deserializeDouble(reader);

        // Read ending of object
        reader.getNextToken(); // }

        // Update values
        update(id, price);
    } while (reader.getNextToken() == ',');
}

It's working fine, but I'm not sure this is the fastest way of doing this as I barely know DSL-JSON api.

How can I increase the performance?

@zapov
Copy link
Member

zapov commented May 31, 2018

Ideally you shouldn't try to write manual parsing with DSL-JSON (except for some custom types) since there should be no overhead with using high level API consuming compile time bindings. But your code looks fine. There are two minor things you could improve:

  1. You can try skipping over the names, since fillName will calculate hash of the value, but since you don't use it, you can just call reader.skip() instead.
  2. You can try and reusing string values from the cache instead of allocating new string all the time. Not sure if that will help, but its something to try. You can do that by initializing library with: https://github.com/ngs-doo/dsl-json/blob/master/library/src/main/java/com/dslplatform/json/DslJson.java#L229

Also, since you are not really using compile time bindings, you don't need that withRuntime or includeServiceLoader (at least not for this example). It doesn't affect your code, so you don't need to remove it though.

And if you have control over the JSON message, you can change the format no to be { "id": "foo", "price": num } but rather into ["foo", num] or as a list [ ["foo1",num1], ["foo2",num2] ]

@emmx
Copy link
Author

emmx commented May 31, 2018

Regarding compile time bindings

I thought this method would result in the least overhead possible. I'm curious now how you achieved no overhead with bindings. Any particular example I should check in examples/?

I'm parsing it manually because I have multiple versions of the same parser, depending on what API I'm consuming, so this way the parser is isolated and stored in each FooApiInterface. Maybe I should check the other way of doing this and refactor the code if it turns out to have the same performance but is simpler...

Regarding StringCache

I have implemented a StringCache for this purpose, it is pretty similar to your SimpleStringCache except it handles hash collisions nicely, all with zero allocation. Check CollisionlessStringCache.

DslJson.Settings<Object> settings = new DslJson.Settings<>()
       .useStringValuesCache(new StringCache(512));
DslJson<Object> dslJson = new DslJson<>(settings);
JsonReader reader = dslJson.newReader();
// ...

UPDATE: In a quick test I've seen no increase in performance with either SimpleStringCache or my CollisionlessStringCache, I'm guessing creating new strings always is faster than the overhead added by those classes, specially if the strings are short (4-6 chars long) like in my case.

@zapov
Copy link
Member

zapov commented Jun 1, 2018

There is a bind interface for mutable objects: https://github.com/ngs-doo/dsl-json/blob/master/library/src/main/java/com/dslplatform/json/JsonReader.java#L1110
which you can use to fill the object instance with values without allocating that object instance.
There is no example on how to use it here (outside of tests) :(

I would consider any scenario in which writing code by hand yields significantly better results an issue to fix. Usually there is no real reason why similar code cant be created by the annotation processor.

@emmx emmx closed this as completed Jun 13, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants