microsoft / cppgraphqlgen

C++ GraphQL schema service generator
MIT License
325 stars 45 forks source link

Experiment with resolver visitor pattern instead of always going through `service::ResolverResult`. #320

Closed wravery closed 1 week ago

wravery commented 2 weeks ago

Not sure this is going to work, at least not with better performance. The problem is the entries in a map or list need to be added in the correct order, which means the visitor methods need to be called in that order. I can get it to do that, but it ends up serializing all of the resolvers, whereas without that, resolvers can run in parallel, and the results can be gathered from nested fields and merged together in order as they complete.

With the client_benchmark performing 100000 iterations on my laptop in high performance mode, I'm currently getting a max throughput of about 33k req/s on the next branch, and the resolver-visitor branch is only getting about 31k req/s. The resolver-visitor branch is also not passing unit tests right now because the BlockingAsyncExpensive case actually tests that all of the resolvers are allowed to run in parallel, and because it needs to serialize access to the visitor, the resolver-visitor branch cannot do that, at least not without adding another thread. I haven't been able to come up with an elegant enough awaitable type for the visitor itself to be able to make the later resolvers wait and resume the first one without blocking.

wravery commented 2 weeks ago

Here's a link to the resolver-visitor branch, I'll keep it around for now. But I'm going to shelve this issue unless someone else wants to pick it up.

wravery commented 2 weeks ago

I decided I was over complicating it by trying to turn the visitor into another awaitable and defer execution till it was done. Instead, I'm accumulating a list of "tokens" and then playing them back against the visitor when the resolvers have all finished. The list of tokens can be built in arbitrary orders or in parallel and spliced together without additional copies.

wravery commented 2 weeks ago

Here's a link to the simplified approach in visitor-queue. I was able to eek out a little more performance from client_benchmark (about 3%) with a prototype state machine visitor building the client Response from the ValueTokenStream. Now I'm investigating what it will take to auto-generate the visitor object complete with a state machine that bypasses conversion to a rersponse::Value.