Motivation:
The recent in-box JSON serializer APIs (see https://github.com/dotnet/corefx/issues/34372 / https://github.com/dotnet/apireviews/tree/master/2019/System.Text.Json-Serialization) expect to take PipeReader/PipeWriter. This results in System.Text.Json depending on System.IO.Pipelines. However, the Pipelines package is not part of the shared framework and hence cannot be referenced by S.T.Json.
See discussion here:
https://github.com/dotnet/apireviews/pull/91#discussion_r256595035
Can we move parts of System.IO.Pipelines (or all of it) in-box?
If we consider Pipeline APIs "siblings" to streams, then they could be pushed down low enough within the stack for S.T.Json to take a dependency on it (but maybe not low enough to be pushed to corelib). Is that an appropriate view of pipelines? What are the risks/constraints with moving System.IO.Pipelines inbox?
Possible alternatives to resolve the motivation differently:
1) The JSON serializer instead accepts some other abstraction that is implemented within System.Memory (an assembly it already depends on).
- For example, on the writer/serializer side, an extension of the IBufferWriter interface, IAsyncBufferWriter which PipeWriter would implement (TBD for the reader/deserializer side).
2) We invert the dependency where Pipelines depends on S.T.Json and PipeReader/Writer themselves provide serialize methods.
3) We only move parts of S.IO.Pipelines in-box (i.e. only what's required - PipeReader/PipeWriter) as part of a new assembly. Does that result in freezing the OOB package?
4) The JSON serializer doesn't provide direct PipeReader/PipeWriter support at all (less than ideal).
cc @davidfowl, @steveharter, @pakrym, @joshfree, @terrajobst, @jkotas, @stephentoub, @bartonjs, @ericstj, @KrzysztofCwalina
on the writer/serializer side, an extension of the
IBufferWriterinterface,IAsyncBufferWriter
This seems to be the direction we started heading towards when we have introduced IBufferWriter interface. Do we understand what would the design of these interfaces look like?
The JSON serializer doesn't provide direct
PipeReader/PipeWritersupport at all (less than ideal).
Do you have a number for how much performance is going to be left on the table if we do nothing? (e.g. in TE benchmarks)
I don鈥檛 understand the question Jan. ASP.NET Core is on the path to pipelines (we鈥檙e exposing it in our public API and implanting it natively in kestrel and all of the servers).
The left on the table question IMO is irrelevant. We need to add pipelines support to the serializer for all ASP.NET Core developers, that鈥檚 the path we鈥檙e currntly on and this is a step in that direction.
That鈥檚 said, we can totally introduce new abstractions that we think are more core than pipelines and stick them in corlib or (System.Buffers) as long as it looks similar 馃槵. At that point why not just push pipelines all the way down.
There鈥檚 a 5th option to add to the list that I also hate but for the sake of completeness:
The left on the table question IMO is irrelevant.
The write up says "less than ideal" without additional explanation. I have asked regular manager-type question to quantify it.
ASP.NET Core is on the path to pipeline
That's fine. Pipelines are fine tuned for webserver workload. It makes sense to use them in ASP.NET plumbing.
just push pipelines all the way down.
The pipeline looks very complex to me (e.g. compared to Stream). Maybe it needs to be as complex. I do not know. It is the reason for the second question.
Do you have a number for how much performance is going to be left on the table if we do nothing? (e.g. in TE benchmarks)
I don't have perf numbers for not directly supporting PipeReader/PipeWriter, especially since the serializer isn't fully baked yet/utilized within aspnet. It would depend on what the usage would look like to support pipelines with the other API overloads. @steveharter, could you help with getting some preliminary measurements?
The write up says "less than ideal" without additional explanation. I have asked regular manager-type question to quantify it.
Other than potential perf loss (which I agree needs to be quantified), that comment comes mainly from a usability perspective on behalf of up-stack usages within the aspnetcore repos which becomes more difficult as more of it depends on pipelines (i.e. all usages would have to work around this limitation). Any library developer depending on pipelines would have this usability concern as well.
That's fine. Pipelines are fine tuned for webserver workload. It makes sense to use them in ASP.NET plumbing.
They're not, they are just an abstraction like Streams. Usable for doing any IO. Client or server or anything else really (that's why the stream adapters are so easy to write).
I don't have perf numbers for not directly supporting PipeReader/PipeWriter, especially since the serializer isn't fully baked yet/utilized within aspnet. It would depend on what the usage would look like to support pipelines with the other API overloads. @steveharter, could you help with getting some preliminary measurements?
While I think we should have these, this should not be part of this discussion, so lets not discuss performance here.
The pipeline looks very complex to me (e.g. compared to Stream). Maybe it needs to be as complex. I do not know. It is the reason for the second question.
I'll leave this code here:
Stream code:
Pipe code:
"Complex" is in the eye of the beholder 馃槃
lets not discuss performance here.
If the performance is not a factor, then we can pass Stream everywhere and be done with it. No?
My understanding was that the reason for doing this is performance. Pipelines have a lot of overlap with streams. The added value of pipelines over System.IO.Stream is cooperative buffer management protocol that allows you to avoid a memory copy and throttle amount of buffering. Both these are performance optimizations.
I'll leave this code here:
IMHO, the difference has more to do with the fact that this code was written for pipelines first and stream second. If it was done the other way around, the pipelines code would be more complex and the streams code would be simpler.
We already have streams everywhere. Performance is a factor but I don鈥檛 want this discussion to turn into streams vs pipelines.
Instead I鈥檇 like to discuss and agree on a couple of things:
I鈥檓 ok going in the direction of thin abstractions being pulled lower into the stack as long as we don鈥檛 lose the benefits of the abstractions.
Fair enough. So this issue should rather be called: "Decide on guidelines for using pipelines abstractions in netcoreapp".
Spoke to @stephentoub and he's OK with this being part of .NET Core App. There's nothing confirmed about whether we actually use it anywhere yet though.
Most helpful comment
Spoke to @stephentoub and he's OK with this being part of .NET Core App. There's nothing confirmed about whether we actually use it anywhere yet though.