Improve JsonSerializer.ReadAsync(Stream) throughput (dotnet/corefx#35823)
authorStephen Toub <stoub@microsoft.com>
Thu, 7 Mar 2019 04:49:58 +0000 (20:49 -0800)
committerGitHub <noreply@github.com>
Thu, 7 Mar 2019 04:49:58 +0000 (20:49 -0800)
commit0df563d9cbc76792430604d8f1e7b258f8e25d45
tree5a76040d673bc2bdbfed6f11c48d695f38c3add0
parent192ea4865c927b863aafd2386f95dc93e3ddb3a9
Improve JsonSerializer.ReadAsync(Stream) throughput (dotnet/corefx#35823)

* Improve JsonSerializer.ReadAsync(Stream) throughput

Some low hanging fruit:
- The method was using the Stream.ReadAsync overload that returns a `Task<int>`.  Changed it to take a `Memory<byte>` so that it instead returns a `ValueTask<int>`.
- The method was clearing the full rented buffer upon returning it to the pool, even when only using a small portion of it.  Changed it to only clear what was used.
- The method was resizing the buffer unnecessarily due to faulty logic around how much data remained.  Fixed it to only resize when more than half the buffer is full, which was the original intention.
- The ReadCore method is a bit chunky to call, initializing a new Utf8JsonReader each time, copying large structs, etc.  Since we need to read all of the data from the stream anyway, I changed it to try to fill the buffer, which then minimizes the number of times we need to call ReadCore, in particular avoiding the extra empty call at the end.  We can tweak this further in the future as needed, e.g. only making a second attempt to fill the buffer rather than doing so aggressively.
- Also fixed the exception to contain the full amount of data read from the stream, not just from the most recent call.

* Address PR feedback

Commit migrated from https://github.com/dotnet/corefx/commit/7d1a6b0548cb1fb74e2d3e7da4237e2ca56559e8
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.Stream.cs
src/libraries/System.Text.Json/tests/Serialization/Stream.WriteTests.cs
src/libraries/System.Text.Json/tests/System.Text.Json.Tests.csproj