Support missing for contextual deserializer/serializer
See original GitHub issueRight now, the code directly hooks into the legacy .Serializer
/ .Deserializer
, which provides access to the Func<T, byte[]>
etc, however IMO this violates the API.
The primary API is now the contextual serializer, by which I mean:
- Grpc.Core[.Api] always uses the contextual serializer (except for some tests)
- the contextual serializer always works (it is emulated when initialized from the legacy API), where-as the legacy serializer does not; see Marshaller.cs 44-47
// gRPC only uses contextual serializer/deserializer internally, so emulating the legacy
// (de)serializer is not necessary.
this.serializer = (msg) => { throw new NotImplementedException(); };
this.deserializer = (payload) => { throw new NotImplementedException(); };
This has two significant problems:
- any custom framework that tries to use the contextual serializer will not work from grpc-dotnet
- any improvements made to the core implementation of
Marshaller
will not be automatically exposed
For context on 2, see this PR, which does an in-place upgrade on how regular protoc-style protobuf deserializes, using the contextual API to significantly reduce buffer allocations. If grpc-dotnet does not use the contextual API: it will not benefit if/when those changes get merged.
I am aware of https://github.com/grpc/grpc-dotnet/issues/30, but IMO there are two different things:
- #30 is about making better use of these APIs in the future
- this report is about a fundamental bug that breaks the API today
You can also probably infer from this that I’m keen on using the contextual API, and generally improving this space - presumably looking into a new writer API too.
So, I guess my main point here is: grpc-dotnet should not use the legacy API - it should switch to the contextual API. I can offer some help with that if it would be welcome.
As a caveat / disclosure thing: I will acknowledge the remark:
/// Note: experimental API that can change or be removed without any prior notice.
but… if the API surface changes, consumers need to update anyway. I don’t personally see this as a reason not to consume this API.
Issue Analytics
- State:
- Created 4 years ago
- Reactions:1
- Comments:9 (9 by maintainers)
Top GitHub Comments
I have plans to remove almost all non-message allocations on the server. I don’t want to micro-optimize for the serialization context if code will be thrown away post 3.0.
You and me have very different views on allocations 😃
Right now I’m on a treasure-hunt for avoidable allocations in the Grpc.Core/Grpc.Core.Api path (the latter of which you should benefit from indirectly); I would do the same for Grpc-Dotnet, but … it is kinda awkward to work with right now unless I keep separate machines/VMs for preview6 and preview7 - and even then, it isn’t the easiest build since the dependency-tree is fast-moving.
But in all seriousness; if you can avoid an alloc per call (without bending the code too far out of shape), IMO you should avoid that alloc per call; they add up surprisingly quickly, and can quickly swamp the necessary allocations (i.e. the actual data payloads); on a high-throughput server allocations and GC can quickly dominate, or at least make a server more expensive than it needs to be (which can mean in terms of overhead on a box, or actual hosting costs for cloud/hosted services), even if performance is still acceptable.