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
[API Proposal]: JsonSerializerOptions.UseZeroByteReads #77935
Comments
Tagging subscribers to this area: @dotnet/area-system-text-json, @gregsdennis Issue DetailsBackground and motivationZero-byte reads are a technique used in our networking stacks (System.Net, ASP.NET, YARP) to defer renting/allocating memory until there's data available on the socket. With Json, this would help in cases where the whole object hasn't been read into memory yet. Starting with .NET 7.0, the streams returned by Prior art:
@davidfowl I assume this wouldn't do much in ASP.NET since the API Proposalnamespace System.Text.Json;
public sealed class JsonSerializerOptions
{
// New property on existing type
public bool UseZeroByteReads { get; set; }
} API Usageprivate static readonly JsonSerializerOptions s_jsonOptions = new() { UseZeroByteReads = true };
public static IAsyncEnumerable<Foo> DeserializeAsync(Stream stream) =>
JsonSerializer.DeserializeAsyncEnumerable<Foo>(stream, s_jsonOptions); Alternative DesignsIf the json implementation isn't capable of deferring allocations of its own buffers while waiting for more data, the user could achieve similar performance gains by implementing their own RisksYARP always uses zero-byte reads on HTTP bodies. We've seen in the past that some implementations of If the user runs into such a scenario, they should fix that
|
@MihaZupan Stream.Read/ReadAsync are documented that zero bytes means EOF (last sentence specifically):
If that is no longer true should we change the docs? IMO we're working correctly here, I think it makes more sense for you to create stream wrapper if you prefer different to default behavior. Possibly it makes more sense to add that flag to Stream itself? |
The zero here refers to the input, i.e. asking for zero bytes. |
@MihaZupan I'm marking this as Future for now. If this is impacting your scenario significantly or if you're planning to contribute please let me know and we can bump priority. We will unlikely have time to address this in 8.0 otherwise. |
I suppose another alternative design here would be for |
I feel like this doesn't belong to the JsonSerializerOptions. It's something too low level compared to what's in the option IMO. As a user I am expecting to find details about serialization convention, case handling and what not there, not low level details about how the serializer allocates memory while reading from a stream. My suggestion is to always do zero bytes read and eventually, if you really want to have a switch, implement it via AppContext or something alike. Just my 2 cent :) |
Any thoughts on this @dotnet/area-system-text-json: #77935 (comment)? |
I agree with @ilmax here. I think if profitable, STJ should just implement this. Zero byte reads are now used in other places in BCL by default. |
Background and motivation
Zero-byte reads are a technique used in our networking stacks (System.Net, ASP.NET, YARP) to defer renting/allocating memory until there's data available on the socket.
This can greatly reduce memory usage in applications with a lot of concurrent operations.
In the case of YARP, we've seen a 10x reduction in process memory consumption when used with WebSockets.
With Json, this would help in cases where the whole object hasn't been read into memory yet.
An API that would benefit greatly is
JsonSerializer.DeserializeAsyncEnumerable
which can be long-lived and spend a lot of time just waiting on IO.Starting with .NET 7.0, the streams returned by
HttpClient
are able to take advantage of this technique.System.Net.Http.Json
extensions are therefore a prime candidate where we should strongly consider enabling this option by default.Prior art:
StreamPipeReaderOptions.UseZeroByteReads
fromSystem.IO.Pipelines
(Add ability to perform zero byte reads in StreamPipeReader #37539)SocketTransportOptions.WaitForDataBeforeAllocatingBuffer
from Kestrel@davidfowl I assume this wouldn't do much in ASP.NET since the
HttpContext.Body
already does zero-byte reads internally, right? That is unless the json implementation would be able to defer allocating its own buffers on top of using ZBRs on the underlying transport.API Proposal
API Usage
Alternative Designs
If the json implementation isn't capable of deferring allocations of its own buffers while waiting for more data, the user could achieve similar performance gains by implementing their own
Stream
wrapper that performed zero-byte reads and passing that toJsonSerializer
instead.The text was updated successfully, but these errors were encountered: