Skip to content
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

Use Json.NET support for Streams in NewtonSoftJsonSerializer #5376

Open
wants to merge 5 commits into
base: dev
Choose a base branch
from

Conversation

thzinc
Copy link

@thzinc thzinc commented Nov 10, 2021

Includes a new benchmark test for serializing and deserialzing especially large messages..

Before

BenchmarkDotNet=v0.13.1, OS=macOS Big Sur 11.6.1 (20G224) [Darwin 20.6.0]
Intel Core i9-9880H CPU 2.30GHz, 1 CPU, 16 logical and 8 physical cores
.NET SDK=6.0.100
  [Host]     : .NET Core 3.1.21 (CoreCLR 4.700.21.51404, CoreFX 4.700.21.51508), X64 RyuJIT
  Job-AXOSYP : .NET Core 3.1.21 (CoreCLR 4.700.21.51404, CoreFX 4.700.21.51508), X64 RyuJIT

IterationCount=10  
Method Mean Error StdDev Gen 0 Allocated
Json_serializer_message_roundtrip 21.29 μs 0.860 μs 0.512 μs 1.5667 13 KB
Json_serializer_large_message_roundtrip 19.97 μs 0.844 μs 0.558 μs 1.5000 13 KB

After

BenchmarkDotNet=v0.13.1, OS=macOS Big Sur 11.6.1 (20G224) [Darwin 20.6.0]
Intel Core i9-9880H CPU 2.30GHz, 1 CPU, 16 logical and 8 physical cores
.NET SDK=6.0.100
  [Host]     : .NET Core 3.1.21 (CoreCLR 4.700.21.51404, CoreFX 4.700.21.51508), X64 RyuJIT
  Job-KXPLPC : .NET Core 3.1.21 (CoreCLR 4.700.21.51404, CoreFX 4.700.21.51508), X64 RyuJIT

IterationCount=10  
Method Mean Error StdDev Gen 0 Allocated
Json_serializer_message_roundtrip 8.178 μs 0.3296 μs 0.1724 μs 1.8000 15 KB
Json_serializer_large_message_roundtrip 8.468 μs 0.5805 μs 0.3036 μs 1.8000 15 KB

Copy link
Member

@Aaronontheweb Aaronontheweb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great - seems like a safe change; will wait on CI to tell me otherwise if I'm wrong.

FYI: we just merged in .NET 6 support today and it appears to have caused some regressions in the way the .NET Threadpool behaves. I'm still investigating that, but if there are unrelated unit tests that fail on your PR don't panic - we have a number of chronically racy tests that we've been gradually fixing but it looks like .NET 6 made that problem worse.

@@ -47,6 +56,16 @@ public void Json_serializer_message_roundtrip()
}
}

[Benchmark(OperationsPerInvoke = Operations)]
public void Json_serializer_large_message_roundtrip()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

using (var writer = new StreamWriter(stream))
{
_serializer.Serialize(writer, obj);
return stream.ToArray();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

using (var reader = new JsonTextReader(r))
{
object res = _serializer.Deserialize(reader);
return TranslateSurrogate(res, this, type);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@Aaronontheweb Aaronontheweb enabled auto-merge (squash) November 10, 2021 22:37
@Aaronontheweb
Copy link
Member

And thanks for adding the benchmark too - that made this PR much easier to review.

@Aaronontheweb
Copy link
Member

Ah, looks like all of the F# Serialization specs just blew up

Copy link
Member

@Aaronontheweb Aaronontheweb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like we broke the F# DU serialization tests.

cc @to11mtm - I can't recall of this is the case or not, but is it safe to re-use the same _serializer instance on multiple threads concurrently?

using (var r = new StreamReader(stream))
using (var reader = new JsonTextReader(r))
{
object res = _serializer.Deserialize(reader);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the Settings are passed in properly here when the _serializer is created - is the issue that the _serializer class isn't meant to be used concurrently or is it that JsonConvert is doing something differently than _serializer.Deserialize?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking into this now

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, looks like the StreamWriter used in ToBinary above needs to be flushed/disposed before attempting to return the byte[]. Will push an updated commit after re-running tests locally.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you re-run the benchmarks also?

{
for (int i = 0; i < Operations; i++)
{
var bytes = json.ToBinary(message);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I totally missed this copypasta. Working on fix and will include fresh runs of benchmarks.

using (var r = new StreamReader(stream))
using (var reader = new JsonTextReader(r))
{
object res = _serializer.Deserialize(reader);
Copy link
Member

@to11mtm to11mtm Nov 11, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We cannot trust the Thread safety of JsonSerializer in it's present state. You either have to create a new Serializer each time or use the static methods (which do so themselves)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dang, that's disappointing. Why does the current implementation hold on to a reference of an instance of the serializer then?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dang, that's disappointing. Why does the current implementation hold on to a reference of an instance of the serializer then?

No idea; we probably don't need to have it anymore. Although having a ThreadStatic reference to it might not be the worst thing in the world, in combination with your changes.

@thzinc
Copy link
Author

thzinc commented Nov 11, 2021

I'm going to have to put this work on hold. There's a surprising performance difference between StringBuilder+StringWriter and MemoryStream+StreamWriter and I don't have time in the near term to work it out. I'll come back to this in a bit.

…memory during serialization/deserialization

Also included separate benchmarks to identify performance differences between serialization and deserialization
… JsonSerializer and improve performance for serializing and deserializing large objects.

Based on [recommendation from Json.NET docs](https://www.newtonsoft.com/json/help/html/Performance.htm#MemoryUsage)
auto-merge was automatically disabled November 12, 2021 08:28

Head branch was pushed to by a user without write access

@thzinc thzinc force-pushed the use-streaming-api-for-newtonsoftjsonserializer branch from 465b6b8 to 06368e6 Compare November 12, 2021 08:28
@thzinc
Copy link
Author

thzinc commented Nov 12, 2021

This latest push is a bit deeper than the initial attempt at updating the NewtonSoftJsonSerializer.

Much to my surprise, using MemoryStream + StreamWriter/StreamReader is less efficient than using StringBuffer + StringWriter and Encoding.GetString() + StringReader with Json.NET. I suspect the BCL's StreamWriter and StreamReader are doing work more often to buffer bytes in order to encode or decode strings.

I broke out the different duties that were being handled in SurrogateConverter into distinct internal implementations of JsonConverter. I'm very open to feedback on this.

Latest benchmarks

The initial work included a bug that did not properly flush the stream in ToBinary() and resulted in an exaggerated improvement in performance. After a lot of iteration on the code, the actual improvement is much more subtle.

In summary, I worked to get performance parity with the "before" for small messages and an improvement for large messages.

Before

BenchmarkDotNet=v0.13.1, OS=macOS Big Sur 11.6.1 (20G224) [Darwin 20.6.0]
Intel Core i9-9880H CPU 2.30GHz, 1 CPU, 16 logical and 8 physical cores
.NET SDK=6.0.100
  [Host]     : .NET Core 3.1.21 (CoreCLR 4.700.21.51404, CoreFX 4.700.21.51508), X64 RyuJIT
  Job-FMTJAV : .NET Core 3.1.21 (CoreCLR 4.700.21.51404, CoreFX 4.700.21.51508), X64 RyuJIT

IterationCount=10  
Method Mean Error StdDev Gen 0 Gen 1 Allocated
Json_serializer_message_roundtrip 18.327 μs 0.4767 μs 0.2837 μs 1.5667 - 13 KB
Json_serializer_message_to_binary 6.193 μs 0.2184 μs 0.1142 μs 0.7250 - 6 KB
Json_serializer_message_from_binary 7.846 μs 0.2756 μs 0.1823 μs 0.8429 - 7 KB
Json_serializer_large_message_roundtrip 4,012.253 μs 69.6297 μs 41.4355 μs 392.0000 95.0000 3,210 KB
Json_serializer_large_message_to_binary 1,017.065 μs 28.0530 μs 14.6723 μs 57.0000 1.0000 469 KB
Json_serializer_large_message_from_binary 3,029.812 μs 59.0983 μs 39.0899 μs 333.0000 1.0000 2,742 KB

After

BenchmarkDotNet=v0.13.1, OS=macOS Big Sur 11.6.1 (20G224) [Darwin 20.6.0]
Intel Core i9-9880H CPU 2.30GHz, 1 CPU, 16 logical and 8 physical cores
.NET SDK=6.0.100
  [Host]     : .NET Core 3.1.21 (CoreCLR 4.700.21.51404, CoreFX 4.700.21.51508), X64 RyuJIT
  Job-KKWJDG : .NET Core 3.1.21 (CoreCLR 4.700.21.51404, CoreFX 4.700.21.51508), X64 RyuJIT

IterationCount=10  
Method Mean Error StdDev Gen 0 Gen 1 Allocated
Json_serializer_message_roundtrip 17.847 μs 0.9000 μs 0.5953 μs 1.5000 - 12 KB
Json_serializer_message_to_binary 5.940 μs 0.2003 μs 0.1047 μs 0.6889 - 6 KB
Json_serializer_message_from_binary 8.931 μs 0.4962 μs 0.2953 μs 0.8000 - 7 KB
Json_serializer_large_message_roundtrip 3,726.512 μs 49.3006 μs 32.6093 μs 384.0000 84.0000 3,139 KB
Json_serializer_large_message_to_binary 873.565 μs 14.9581 μs 8.9013 μs 57.0000 1.0000 469 KB
Json_serializer_large_message_from_binary 2,768.204 μs 26.0914 μs 17.2579 μs 326.0000 78.0000 2,671 KB

@thzinc
Copy link
Author

thzinc commented Nov 12, 2021

Looks like the Akka.DistributedData.Tests.Serialization.ReplicatedDataSerializerSpec.ReplicatedDataSerializer_should_serialize_GSet failure is caused by the test doing byte-by-byte assertions and the newly-reused serializer's own reference counter doesn't reset between serializations. It's not a failure, per se, but it does result in valid output that is technically accurate. The $id property isn't guaranteed to be coherent outside of the JSON result.

Serialized "{\"$id\":\"7\",\"$type\":\"Akka.Cluster.UniqueAddress, Akka.Cluster\",\"Address\":{\"$id\":\"8\",\"$type\":\"Akka.Actor.Address+AddressSurrogate, Akka\",\"Protocol\":\"akka.tcp\",\"System\":\"ReplicatedDataSerializerSpec\",\"Host\":\"some.host.org\",\"Port\":4711},\"Uid\":{\"$\":\"I1\"}}"
Serialized "{\"$id\":\"9\",\"$type\":\"Akka.Cluster.UniqueAddress, Akka.Cluster\",\"Address\":{\"$id\":\"10\",\"$type\":\"Akka.Actor.Address+AddressSurrogate, Akka\",\"Protocol\":\"akka.tcp\",\"System\":\"ReplicatedDataSerializerSpec\",\"Host\":\"other.host.org\",\"Port\":4711},\"Uid\":{\"$\":\"I2\"}}"
Serialized "{\"$id\":\"11\",\"$type\":\"Akka.Cluster.UniqueAddress, Akka.Cluster\",\"Address\":{\"$id\":\"12\",\"$type\":\"Akka.Actor.Address+AddressSurrogate, Akka\",\"Protocol\":\"akka.tcp\",\"System\":\"ReplicatedDataSerializerSpec\",\"Host\":\"some.host.org\",\"Port\":4711},\"Uid\":{\"$\":\"I3\"}}"
serializing blobB
Serialized "{\"$id\":\"13\",\"$type\":\"Akka.Cluster.UniqueAddress, Akka.Cluster\",\"Address\":{\"$id\":\"14\",\"$type\":\"Akka.Actor.Address+AddressSurrogate, Akka\",\"Protocol\":\"akka.tcp\",\"System\":\"ReplicatedDataSerializerSpec\",\"Host\":\"some.host.org\",\"Port\":4711},\"Uid\":{\"$\":\"I1\"}}"
Serialized "{\"$id\":\"15\",\"$type\":\"Akka.Cluster.UniqueAddress, Akka.Cluster\",\"Address\":{\"$id\":\"16\",\"$type\":\"Akka.Actor.Address+AddressSurrogate, Akka\",\"Protocol\":\"akka.tcp\",\"System\":\"ReplicatedDataSerializerSpec\",\"Host\":\"other.host.org\",\"Port\":4711},\"Uid\":{\"$\":\"I2\"}}"
Serialized "{\"$id\":\"17\",\"$type\":\"Akka.Cluster.UniqueAddress, Akka.Cluster\",\"Address\":{\"$id\":\"18\",\"$type\":\"Akka.Actor.Address+AddressSurrogate, Akka\",\"Protocol\":\"akka.tcp\",\"System\":\"ReplicatedDataSerializerSpec\",\"Host\":\"some.host.org\",\"Port\":4711},\"Uid\":{\"$\":\"I3\"}}"

@thzinc
Copy link
Author

thzinc commented Nov 12, 2021

Looks like it's a very related issue for the ConsistentHashingRouterSpec failures. The $id property changes the hashing result (because the hashing is based on serializing the key), breaking the consistent hashing functionality.

@thzinc
Copy link
Author

thzinc commented Nov 15, 2021

Reviewed more specifics of how Json.NET's internal DefaultReferenceResolver works and implemented a suitable replacement here.

The IReferenceResolver implementation in Json.NET is one of the main issues with JsonSerializer's thread-safety. I think within the bounds of this implementation in Akka.net, the issue is mitigated with this implementation and use of IReferenceResolver.

Benchmarks

Re-ran benchmarks against this update and the results look about as good as they did before

Before

BenchmarkDotNet=v0.13.1, OS=macOS Big Sur 11.6.1 (20G224) [Darwin 20.6.0]
Intel Core i9-9880H CPU 2.30GHz, 1 CPU, 16 logical and 8 physical cores
.NET SDK=6.0.100
  [Host]     : .NET Core 3.1.21 (CoreCLR 4.700.21.51404, CoreFX 4.700.21.51508), X64 RyuJIT
  Job-CDLPJT : .NET Core 3.1.21 (CoreCLR 4.700.21.51404, CoreFX 4.700.21.51508), X64 RyuJIT

IterationCount=10  
Method Mean Error StdDev Gen 0 Gen 1 Allocated
Json_serializer_message_roundtrip 20.216 μs 0.5475 μs 0.3621 μs 1.5500 0.0500 13 KB
Json_serializer_message_to_binary 6.783 μs 0.2226 μs 0.1472 μs 0.7250 - 6 KB
Json_serializer_message_from_binary 8.384 μs 0.1417 μs 0.0937 μs 0.8500 0.0167 7 KB
Json_serializer_large_message_roundtrip 4,236.075 μs 119.8522 μs 79.2748 μs 392.0000 1.0000 3,210 KB
Json_serializer_large_message_to_binary 1,155.338 μs 37.2496 μs 22.1666 μs 57.0000 7.0000 469 KB
Json_serializer_large_message_from_binary 3,135.823 μs 51.2496 μs 26.8046 μs 333.0000 1.0000 2,742 KB

After

BenchmarkDotNet=v0.13.1, OS=macOS Big Sur 11.6.1 (20G224) [Darwin 20.6.0]
Intel Core i9-9880H CPU 2.30GHz, 1 CPU, 16 logical and 8 physical cores
.NET SDK=6.0.100
  [Host]     : .NET Core 3.1.21 (CoreCLR 4.700.21.51404, CoreFX 4.700.21.51508), X64 RyuJIT
  Job-HWSFHK : .NET Core 3.1.21 (CoreCLR 4.700.21.51404, CoreFX 4.700.21.51508), X64 RyuJIT

IterationCount=10  
Method Mean Error StdDev Gen 0 Gen 1 Allocated
Json_serializer_message_roundtrip 19.833 μs 0.8208 μs 0.5429 μs 1.5000 - 12 KB
Json_serializer_message_to_binary 6.803 μs 0.1479 μs 0.0978 μs 0.6875 - 6 KB
Json_serializer_message_from_binary 10.053 μs 0.2756 μs 0.1823 μs 0.8000 - 7 KB
Json_serializer_large_message_roundtrip 3,768.048 μs 62.4812 μs 32.6789 μs 384.0000 1.0000 3,139 KB
Json_serializer_large_message_to_binary 918.517 μs 39.9714 μs 26.4386 μs 57.0000 7.0000 469 KB
Json_serializer_large_message_from_binary 2,781.628 μs 36.0304 μs 23.8319 μs 326.0000 79.0000 2,671 KB

@Aaronontheweb
Copy link
Member

@to11mtm what do you make of these latest changes?

(This was formerly handled by TranslateSurrogate())
@thzinc
Copy link
Author

thzinc commented Nov 15, 2021

One more update to resolve the remaining failing tests. Had to reimplement the function that TranslateSurrogate was handling post-serialization in FromBinary

Benchmarks

The difference in results on Json_serializer_large_message_to_binary is curious to me. Might require further investigation.

Before

BenchmarkDotNet=v0.13.1, OS=macOS Big Sur 11.6.1 (20G224) [Darwin 20.6.0]
Intel Core i9-9880H CPU 2.30GHz, 1 CPU, 16 logical and 8 physical cores
.NET SDK=6.0.100
  [Host]     : .NET Core 3.1.21 (CoreCLR 4.700.21.51404, CoreFX 4.700.21.51508), X64 RyuJIT
  Job-VTZTAU : .NET Core 3.1.21 (CoreCLR 4.700.21.51404, CoreFX 4.700.21.51508), X64 RyuJIT

IterationCount=10  
Method Mean Error StdDev Gen 0 Gen 1 Allocated
Json_serializer_message_roundtrip 22.766 μs 2.1552 μs 1.2825 μs 1.5000 - 13 KB
Json_serializer_message_to_binary 7.595 μs 0.5582 μs 0.3692 μs 0.7143 - 6 KB
Json_serializer_message_from_binary 9.649 μs 0.3219 μs 0.2129 μs 0.8000 - 7 KB
Json_serializer_large_message_roundtrip 4,281.663 μs 130.5660 μs 77.6977 μs 392.0000 - 3,210 KB
Json_serializer_large_message_to_binary 1,067.483 μs 23.9397 μs 14.2461 μs 57.0000 1.0000 469 KB
Json_serializer_large_message_from_binary 3,200.049 μs 44.6076 μs 26.5453 μs 333.0000 68.0000 2,742 KB

After

BenchmarkDotNet=v0.13.1, OS=macOS Big Sur 11.6.1 (20G224) [Darwin 20.6.0]
Intel Core i9-9880H CPU 2.30GHz, 1 CPU, 16 logical and 8 physical cores
.NET SDK=6.0.100
  [Host]     : .NET Core 3.1.21 (CoreCLR 4.700.21.51404, CoreFX 4.700.21.51508), X64 RyuJIT
  Job-MKUYFU : .NET Core 3.1.21 (CoreCLR 4.700.21.51404, CoreFX 4.700.21.51508), X64 RyuJIT

IterationCount=10  
Method Mean Error StdDev Gen 0 Gen 1 Allocated
Json_serializer_message_roundtrip 19.652 μs 0.5599 μs 0.3332 μs 1.5000 - 12 KB
Json_serializer_message_to_binary 6.859 μs 0.3664 μs 0.2424 μs 0.6875 - 6 KB
Json_serializer_message_from_binary 9.961 μs 0.4493 μs 0.2972 μs 0.8000 - 7 KB
Json_serializer_large_message_roundtrip 4,044.804 μs 51.3056 μs 30.5311 μs 400.0000 99.0000 3,280 KB
Json_serializer_large_message_to_binary 1,179.838 μs 13.2095 μs 7.8608 μs 74.0000 - 609 KB
Json_serializer_large_message_from_binary 2,806.984 μs 27.1114 μs 16.1336 μs 326.0000 1.0000 2,671 KB

@thzinc
Copy link
Author

thzinc commented Nov 15, 2021

Ah, caught my problem. My last commit moved the I/F/M chars into constants, which required using string interpolation when serializing numbers. The "large message" benchmarks use big lists of int, which helped to expose this slowness.

Benchmarks

Before

BenchmarkDotNet=v0.13.1, OS=macOS Big Sur 11.6.1 (20G224) [Darwin 20.6.0]
Intel Core i9-9880H CPU 2.30GHz, 1 CPU, 16 logical and 8 physical cores
.NET SDK=6.0.100
  [Host]     : .NET Core 3.1.21 (CoreCLR 4.700.21.51404, CoreFX 4.700.21.51508), X64 RyuJIT
  Job-WBVURS : .NET Core 3.1.21 (CoreCLR 4.700.21.51404, CoreFX 4.700.21.51508), X64 RyuJIT

IterationCount=10  
Method Mean Error StdDev Gen 0 Gen 1 Allocated
Json_serializer_message_roundtrip 18.573 μs 0.6832 μs 0.4519 μs 1.5667 - 13 KB
Json_serializer_message_to_binary 6.263 μs 0.1742 μs 0.1036 μs 0.7250 - 6 KB
Json_serializer_message_from_binary 8.799 μs 0.5695 μs 0.3767 μs 0.8000 - 7 KB
Json_serializer_large_message_roundtrip 3,959.167 μs 73.8127 μs 43.9248 μs 392.0000 1.0000 3,210 KB
Json_serializer_large_message_to_binary 1,014.940 μs 22.3383 μs 14.7754 μs 57.0000 1.0000 469 KB
Json_serializer_large_message_from_binary 3,235.140 μs 87.9332 μs 52.3276 μs 333.0000 - 2,742 KB

After

BenchmarkDotNet=v0.13.1, OS=macOS Big Sur 11.6.1 (20G224) [Darwin 20.6.0]
Intel Core i9-9880H CPU 2.30GHz, 1 CPU, 16 logical and 8 physical cores
.NET SDK=6.0.100
  [Host]     : .NET Core 3.1.21 (CoreCLR 4.700.21.51404, CoreFX 4.700.21.51508), X64 RyuJIT
  Job-JVIIBH : .NET Core 3.1.21 (CoreCLR 4.700.21.51404, CoreFX 4.700.21.51508), X64 RyuJIT

IterationCount=10  
Method Mean Error StdDev Gen 0 Gen 1 Allocated
Json_serializer_message_roundtrip 18.988 μs 0.6096 μs 0.4032 μs 1.5000 - 12 KB
Json_serializer_message_to_binary 6.501 μs 0.3866 μs 0.2557 μs 0.6889 0.0111 6 KB
Json_serializer_message_from_binary 9.823 μs 0.4166 μs 0.2756 μs 0.8000 - 7 KB
Json_serializer_large_message_roundtrip 3,758.026 μs 52.8067 μs 31.4244 μs 384.0000 84.0000 3,139 KB
Json_serializer_large_message_to_binary 919.429 μs 51.9114 μs 30.8916 μs 57.0000 7.0000 469 KB
Json_serializer_large_message_from_binary 2,822.913 μs 49.0671 μs 32.4548 μs 326.0000 81.0000 2,671 KB

string data = JsonConvert.SerializeObject(obj, Formatting.None, Settings);
byte[] bytes = Encoding.UTF8.GetBytes(data);
return bytes;
var stringBuilder = new StringBuilder(256);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to pull in my changes for Pooling? If we can get this all to work, it would be nice to get both wins in place (especially since I've been waiting for merge on it for some time.)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll go do that now


public partial class NewtonSoftJsonSerializer
{
internal class PrimitiveNumberConverter : JsonConverter, IObjectConverter
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be sealed?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

switch (primitiveType)
{
case 'I':
convertedValue = int.Parse(numberString, NumberFormatInfo.InvariantInfo);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Aaronontheweb Is it worth getting a TODO comment here reminding us that when we can multitarget, to use Span overloads?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

{
private readonly JsonSerializer _serializer;
private readonly ThreadLocal<JsonSerializer> _serializer;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a fan of ThreadLocal for a number of reasons, but I know that we have other challenges at present. @Aaronontheweb is there a polite way to get this fixed upstream?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Getting this fixed upstream as in:

  • Newtonsoft.Json itself?
  • Akka.NET's overall serialization system?


public partial class NewtonSoftJsonSerializer
{
internal class ReferenceResolver : IReferenceResolver
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering whether adapting This IRefrenceResolver fix, or this one would be better overall and help us avoid the threadlocal? My worry is the performance as well as cognitive overhead of WeakReference in this implementation.

@Aaronontheweb
Copy link
Member

@to11mtm merged your changes but there's some merge conflicts with this PR now - would either you or @thzinc mind taking a look?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants