neuecc / Utf8Json

Definitely Fastest and Zero Allocation JSON Serializer for C#(NET, .NET Core, Unity, Xamarin).
MIT License
2.36k stars 266 forks source link

dynamic deserialization performance #58

Open apobekiaris opened 6 years ago

apobekiaris commented 6 years ago

Hi

I want to deserialize different json strings against the same class. So I did a simple performance test on the approach I followed against servicestack.

            var stopwatch = new Stopwatch();
            string json =
                @"[{""timestamp"":1519218860,""tid"":200145554,""price"":""11078.0"",""amount"":""0.1"",""exchange"":""bitfinex"",""type"":""sell""},{""timestamp"":1519218858,""tid"":200145551,""price"":""11078.27292187"",""amount"":""0.06177235"",""exchange"":""bitfinex"",""type"":""buy""}]";

            stopwatch.Start();
            var trades = Utf8Json.JsonSerializer.Deserialize<dynamic>(Encoding.UTF8.GetBytes(json));
            var tradesList=new List<ITrade>();
            double next = 0;
            foreach (var trade in trades){
                var time = trade["timestamp"];
                var item = new Trade {
                    ID = (long) trade["tid"],
                    TimeStamp = DateTimeOffset.FromUnixTimeMilliseconds((long) time).DateTime,
                    Volume = double.Parse(trade["amount"]),
                    Price = double.Parse(trade["price"])
                };
                tradesList.Add(item);
                next = time;
            }
            stopwatch.Stop();
            stopwatch.ElapsedMilliseconds.ShouldBe(0);

Ellapsed=426

var stopwatch = new Stopwatch();
            string json =
                @"[{""timestamp"":1519218860,""tid"":200145554,""price"":""11078.0"",""amount"":""0.1"",""exchange"":""bitfinex"",""type"":""sell""},{""timestamp"":1519218858,""tid"":200145551,""price"":""11078.27292187"",""amount"":""0.06177235"",""exchange"":""bitfinex"",""type"":""buy""}]";

            stopwatch.Start();
            var jsonArrayObjects = JsonObject.ParseArray(json); //124

            var list = new List<ITrade>();

            foreach (var jsonArrayObject in jsonArrayObjects){
                var item = new Trade {
                    ID = (long) jsonArrayObject.Get<long>("tid"),
                    TimeStamp = DateTimeOffset.FromUnixTimeMilliseconds(jsonArrayObject.Get<long>("timestamp")).DateTime,
                    Volume = jsonArrayObject.Get<double>("amount"),
                    Price = (double) jsonArrayObject.Get<double>("price")
                };
                list.Add(item);
                var next = item.ID;
            }
            stopwatch.Stop();
            stopwatch.ElapsedMilliseconds.ShouldBe(0);`

Ellapsed=125

So my question is obvious is this an expected result? or if not what can I do?

neuecc commented 6 years ago

I've got different result.

image

using ServiceStack.Text;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;

class Program
{
    static void Main(string[] args)
    {
        // warmup
        RunUtf8Json(); RunServiceStack();

        // measure
        for (int i = 0; i < 10; i++)
        {
            Console.WriteLine("Utf8Json    :" + RunUtf8Json() + "ms");
            Console.WriteLine("ServiceStack:" + RunServiceStack() + "ms");
        }
    }

    static double RunUtf8Json()
    {
        var stopwatch = new Stopwatch();
        string json =
            @"[{""timestamp"":1519218860,""tid"":200145554,""price"":""11078.0"",""amount"":""0.1"",""exchange"":""bitfinex"",""type"":""sell""},{""timestamp"":1519218858,""tid"":200145551,""price"":""11078.27292187"",""amount"":""0.06177235"",""exchange"":""bitfinex"",""type"":""buy""}]";

        stopwatch.Start();
        var trades = Utf8Json.JsonSerializer.Deserialize<dynamic>(Encoding.UTF8.GetBytes(json));
        var tradesList = new List<ITrade>();
        double next = 0;
        foreach (var trade in trades)
        {
            var time = trade["timestamp"];
            var item = new Trade
            {
                ID = (long)trade["tid"],
                TimeStamp = DateTimeOffset.FromUnixTimeMilliseconds((long)time).DateTime,
                Volume = double.Parse(trade["amount"]),
                Price = double.Parse(trade["price"])
            };
            tradesList.Add(item);
            next = time;
        }
        stopwatch.Stop();
        return stopwatch.Elapsed.TotalMilliseconds;
    }

    static double RunServiceStack()

    {
        var stopwatch = new Stopwatch();
        string json =
            @"[{""timestamp"":1519218860,""tid"":200145554,""price"":""11078.0"",""amount"":""0.1"",""exchange"":""bitfinex"",""type"":""sell""},{""timestamp"":1519218858,""tid"":200145551,""price"":""11078.27292187"",""amount"":""0.06177235"",""exchange"":""bitfinex"",""type"":""buy""}]";

        stopwatch.Start();
        var jsonArrayObjects = JsonObject.ParseArray(json); //124

        var list = new List<ITrade>();

        foreach (var jsonArrayObject in jsonArrayObjects)
        {
            var item = new Trade
            {
                ID = (long)jsonArrayObject.Get<long>("tid"),
                TimeStamp = DateTimeOffset.FromUnixTimeMilliseconds(jsonArrayObject.Get<long>("timestamp")).DateTime,
                Volume = jsonArrayObject.Get<double>("amount"),
                Price = (double)jsonArrayObject.Get<double>("price")
            };
            list.Add(item);
            var next = item.ID;
        }
        stopwatch.Stop();
        return stopwatch.Elapsed.TotalMilliseconds;
    }
}
public interface ITrade
{
    long ID { get; set; }
    DateTime TimeStamp { get; set; }
    double Volume { get; set; }
    double Price { get; set; }
}

public class Trade : ITrade
{
    public long ID { get; set; }
    public DateTime TimeStamp { get; set; }
    public double Volume { get; set; }
    public double Price { get; set; }
}

Note: Utf8Json's Deserialize<dynamic>(Encoding.UTF8.GetBytes(json)); is slowway, If you can pass utf8 bytes directly gots more fast.