在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
开源软件名称:neuecc/Utf8Json开源软件地址:https://github.com/neuecc/Utf8Json开源编程语言:C# 99.9%开源软件介绍:THIS PROJECT IS ARCHIVED, USE COMMUNITY FORK INSTEAD.Utf8Json - Fast JSON Serializer for C#Definitely Fastest and Zero Allocation JSON Serializer for C#(.NET, .NET Core, Unity and Xamarin), this serializer write/read directly to UTF8 binary so boostup performance. And I adopt the same architecture as the fastest binary serializer, MessagePack for C# that I've developed.
Utf8Json does not beat MessagePack for C#(binary), but shows a similar memory consumption(there is no additional memory allocation) and achieves higher performance than other JSON serializers. The crucial difference is that read and write directly to UTF8 binaries means that there is no overhead. Normaly serialization requires serialize to TargetClass obj1;
// Object to UTF8 byte[]
[Benchmark]
public byte[] Utf8JsonSerializer()
{
return Utf8Json.JsonSerializer.Serialize(obj1, jsonresolver);
}
// Object to String to UTF8 byte[]
[Benchmark]
public byte[] Jil()
{
return utf8.GetBytes(global::Jil.JSON.Serialize(obj1));
}
// Object to Stream with StreamWriter
[Benchmark]
public void JilTextWriter()
{
using (var ms = new MemoryStream())
using (var sw = new StreamWriter(ms, utf8))
{
global::Jil.JSON.Serialize(obj1, sw);
}
} For example, the // ASP.NET Core, OutputFormatter
public class JsonOutputFormatter : IOutputFormatter //, IApiResponseTypeMetadataProvider
{
const string ContentType = "application/json";
static readonly string[] SupportedContentTypes = new[] { ContentType };
public Task WriteAsync(OutputFormatterWriteContext context)
{
context.HttpContext.Response.ContentType = ContentType;
// Jil, normaly JSON Serializer requires serialize to Stream or byte[].
using (var writer = new StreamWriter(context.HttpContext.Response.Body))
{
Jil.JSON.Serialize(context.Object, writer, _options);
writer.Flush();
return Task.CompletedTask;
}
// Utf8Json
// Utf8Json.JsonSerializer.NonGeneric.Serialize(context.ObjectType, context.HttpContext.Response.Body, context.Object, resolver);
}
} The approach of directly write/read from JSON binary is similar to corefxlab/System.Text.Json and corefxlab/System.Text.Formatting. But it is not yet finished and not be general serializer. Corefxlab has UTF8String and C# discussing UTF8String Constants but maybe it is far future. Install and QuickStartThe library provides in NuGet except for Unity. Standard library availables for .NET Framework 4.5 and .NET Standard 2.0.
And official Extension Packages for support other library(ImmutableCollection) or binding for framework(ASP.NET Core MVC).
NuGet page links - Utf8Json, Utf8Json.ImmutableCollection, Utf8Json.UnityShims, Utf8Json.AspNetCoreMvcFormatter for Unity, you can download from releases page. There providing .unitypackage. Unity support details, see Unity section. You can find third-party extension package like Utf8Json.FSharpExtensions for F# types, NServiceBus.Utf8Json or others. QuickStart, you can call var p = new Person { Age = 99, Name = "foobar" };
// Object -> byte[] (UTF8)
byte[] result = JsonSerializer.Serialize(p);
// byte[] -> Object
var p2 = JsonSerializer.Deserialize<Person>(result);
// Object -> String
var json = JsonSerializer.ToJsonString(p2);
// Write to Stream
JsonSerializer.Serialize(stream, p2); In default, you can serialize all public members. You can customize serialize to private, exclude null, change DateTime format(default is ISO8601), enum handling, etc. see the Resolver section. Performance of SerializeThis image is what code is generated when object serializing. // Disassemble generated serializer code.
public sealed class PersonFormatter : IJsonFormatter<Person>
{
private readonly byte[][] stringByteKeys;
public PersonFormatter()
{
// pre-encoded escaped string byte with "{", ":" and ",".
this.stringByteKeys = new byte[][]
{
JsonWriter.GetEncodedPropertyNameWithBeginObject("Age"), // {\"Age\":
JsonWriter.GetEncodedPropertyNameWithPrefixValueSeparator("Name") // ,\"Name\":
};
}
public sealed Serialize(ref JsonWriter writer, Person person, IJsonFormatterResolver jsonFormatterResolver)
{
if (person == null) { writer.WriteNull(); return; }
// WriteRawX is optimize byte->byte copy when we know src size.
UnsafeMemory64.WriteRaw7(ref writer, this.stringByteKeys[0]);
writer.WriteInt32(person.Age); // itoa write directly to avoid ToString + UTF8 encode
UnsafeMemory64.WriteRaw8(ref writer, this.stringByteKeys[1]);
writer.WriteString(person.Name);
writer.WriteEndObject();
}
// public unsafe Person Deserialize(ref JsonReader reader, IJsonFormatterResolver jsonFormatterResolver)
} Object to JSON's main serialization cost is write property name. Utf8Json create cache at first and after that only do memory copy. Optimize part1, concatenate "{", ":" and "." to cached propertyname. Optimize part2, use optimized custom memory copy method(see: UnsafeMemory.cs). Normally memory copy is used Number conversion is often high cost. If target encoding is UTF8 only, we can use Other optimize techniques.
Performance of DeserializeWhen deserializing, requires property name to target member name matching. Utf8Json avoid string key decode for matching, generate automata based IL inlining code. use raw byte[] slice and try to match each // Disassemble generated serializer code.
public sealed class PersonFormatter : IJsonFormatter<Person>
{
// public sealed Serialize(ref JsonWriter writer, Person person, IJsonFormatterResolver jsonFormatterResolver)
public unsafe Person Deserialize(ref JsonReader reader, IJsonFormatterResolver jsonFormatterResolver)
{
if (reader.ReadIsNull()) return null;
reader.ReadIsBeginObjectWithVerify(); // "{"
byte[] bufferUnsafe = reader.GetBufferUnsafe();
int age;
string name;
fixed (byte* ptr2 = &bufferUnsafe[0])
{
int num;
while (!reader.ReadIsEndObjectWithSkipValueSeparator(ref num)) // "}" or ","
{
// don't decode string, get raw slice
ArraySegment<byte> arraySegment = reader.ReadPropertyNameSegmentRaw();
byte* ptr3 = ptr2 + arraySegment.Offset;
int count = arraySegment.Count;
if (count != 0)
{
// match automata per long
ulong key = AutomataKeyGen.GetKey(ref ptr3, ref count);
if (count == 0)
{
if (key == 6645569uL)
{
age = reader.ReadInt32(); // atoi read directly to avoid GetString + int.Parse
continue;
}
if (key == 1701667150uL)
{
name = reader.ReadString();
continue;
}
}
}
reader.ReadNextBlock();
}
}
return new PersonSample
{
Age = age,
Name = name
};
}
} Of course number conversion(decode to string -> try parse) is high cost. Utf8Json directly convert byte[] to number by atoi/atod algorithm. Built-in support typesThese types can serialize by default. Primitives( Utf8Json has sufficient extensiblity. You can add custom type support and has some official/third-party extension package. for example ImmutableCollections( Object SerializationUtf8Json can serialze your own public // JsonSerializer.Serialize(new FooBar { FooProperty = 99, BarProperty = "BAR" });
// Result : {"foo":99}
public class FooBar
{
[DataMember(Name = "foo")]
public int FooProperty { get; set; }
[IgnoreDataMember]
public string BarProperty { get; set; }
} Utf8Json has other option, allows private/internal member serialization, convert property name to camelCalse/snake_case, if value is null does not create property. Or you can use a different DateTime format(default is ISO8601). The details, please read Resolver section. Here is sample. // default serializer change to allow private/exclude null/snake_case serializer.
JsonSerializer.SetDefaultResolver(StandardResolver.AllowPrivateExcludeNullSnakeCase);
var json = JsonSerializer.ToJsonString(new Person { Age = 23, FirstName = null, LastName = "Foo" });
// {"age":23,"last_name":"Foo"}
Console.WriteLine(json); Serialize ImmutableObject(SerializationConstructor)Utf8Json can deserialize immutable object like this.
Utf8Json choose constructor with the most matched argument by name(ignore case).
If can not match automatically, you can specify to use constructor manually by public class CustomPoint
{
public readonly int X;
public readonly int Y;
public CustomPoint(int x, int y)
{
this.X = x;
this.Y = y;
}
// used this constructor.
[SerializationConstructor]
public CustomPoint(int x)
{
this.X = x;
}
} ShouldSerializeXXX patternUtfJson supports ShouldSerialize feature of Json.NET. If defined public class MyPerson
{
public string Name { get; set; }
public string[] Addresses { get; set; }
// ShouldSerialize*membername**
// method must be `public` and return `bool` and parameter less.
public bool ShouldSerializeAddresses()
{
if (Addresses != null && Addresses.Length != 0)
{
return true;
}
else
{
return false;
}
}
}
--
// {"Name":"foo"}
JsonSerializer.ToJsonString(new MyPerson { Name = "foo", Addresses = new string[0] });
// {"Name":"bar","Addresses":["tokyo","kyoto"]}
JsonSerializer.ToJsonString(new MyPerson { Name = "bar", Addresses = new[] { "tokyo", "kyoto" } }); Dynamic DeserializationIf use JsonSerializer.Deserialize or JsonSerializer.Deserialize, convert json to // dynamic json deserialize
var json = JsonSerializer.Deserialize<dynamic>(@"{""foo"":""json"",""bar"":100,""nest"":{""foobar"":true}}");
var r1 = json["foo"]; // "json" - dynamic(string)
var r2 = json["bar"]; // 100 - dynamic(double), it can cast to int or other number.
var r3 = json["nest"]["foobar"]; // true If target is object, you access by string indexer. JSON CommentsJSON Comments is invalid JSON Format but used widely(for example, VSCode - settings.json) and also supports JSON.NET. Utf8Json suports both single-line comment and multi-line comment. {
// allow single line comment
"foo": true, // trailing
/*
allow
multi
line
comment
*/
"bar": 999 /* trailing */
} EncodingUtf8Json only supports UTF-8 but it is valid on latest JSON Spec - RFC8259 The JavaScript Object Notation (JSON) Data Interchange Format, DECEMBER 2017. It mentions about encoding.
Which serializer should be usedThe performance of binary(protobuf, msgpack, avro, etc...) vs text(json, xml, yaml, etc...) depends on the implementation. However, binary has advantage basically. Utf8Json write directly to I recommend use MessagePack for C# for general use serializer, C# to C#, C# to NoSQL, Save to File, communicate internal cross platform(multi-language), etc. MessagePack for C# has many options(Union ,Typeless, Compression) and definitely fastest. But JSON is still better on web, for public Web API, send for JavaScript and easy to integrate between multi-language communication. For example, use Utf8Json for Web API formatter and use MessagePack for C# for Redis. It is perfect. For that reason Utf8Json is focusing performance and cross-platform compatibility. I don't implement original format(like Union, Typeless, Cyclic-Reference) if you want to use it should be use binary serializer. But customizability for serialize/deserialize JSON is important for cross-platform communication. IJsonFormatterResolver can serialize/deserialize all patterns and you can create own pattern. High-Level API(JsonSerializer)
Utf8Json operates at the byte[] level, so High-Level API uses memory pool internaly to avoid unnecessary memory allocation. If result size is under 64K, allocates GC memory only for the return bytes. Low-Level API(IJsonFormatter)IJsonFormatter is serializer by each type. For example public interface IJsonFormatter<T> : IJsonFormatter
{
void Serialize(ref JsonWriter writer, T value, IJsonFormatterResolver formatterResolver);
T Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver);
} Many builtin formatters exists under Utf8Json.Formatters. You can get sub type serializer by 全部评论
专题导读
上一篇:shubheksha/kubernetes-internals: This is a collection of resources that shed lig ...发布时间:2022-07-09下一篇:json-schema-org/json-schema-spec: The JSON Schema I-D sources发布时间:2022-07-08热门推荐
热门话题
阅读排行榜
|
请发表评论