.netservicestackdatacontractservicestack-text

How to optimize ServiceStack.Text performance when deserializing to enums with DataContract


Is there a way to optimize ServiceStack.Text (version 5.4.0) performance when deserializing enumerated values to .Net enums that have DataContract and EnumMember attributes set? I would like to use EnumMember attributes to defined the serialized names, but unfortunately ServiceStack.Text seems to need about three time more time to deserialize using this method, as opposed to deserializing based on plain enum member names.

For example, consider this simple C# test program:

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

namespace ServiceStackPerformance
{
    public class Program
    {
        [DataContract]
        enum DataContractEnum
        {
            [EnumMember(Value = "first")]
            First = 0,
            [EnumMember(Value = "second")]
            Second = 1,
        }

        enum PlainEnum
        {
            first = 0,
            second = 1,
        }

        [DataContract]
        class DataContractEnumList
        {
            [DataMember(Name = "values")]
            public List<DataContractEnum> Values { get; set; }
        }

        [DataContract]
        class PlainEnumList
        {
            [DataMember(Name = "values")]
            public List<PlainEnum> Values { get; set; }
        }

        static void Main(string[] args)
        {
            int size = 100000;
            string test = GenerateTestString(size);
            var stopwatch = new Stopwatch();

            stopwatch.Start();
            var dataContractEnumList = test.FromJson<DataContractEnumList>();
            var dataContractMs = stopwatch.ElapsedMilliseconds;

            stopwatch.Restart();
            var plainType = test.FromJson<PlainEnumList>();
            var plainMs = stopwatch.ElapsedMilliseconds;

            Console.WriteLine($"Deserializing input of size {2*size+1} to data contract enum took {dataContractMs} ms.");
            Console.WriteLine($"Deserializing input of size {2*size+1} to simple enum took {plainMs} ms.");
        }

        private static string GenerateTestString(int size)
        {
            var builder = new StringBuilder(10*size);
            builder.Append("{\"values\":[");
            for ( int i = 0; i < size; i++)
            {
                builder.Append("\"first\",\"second\",");
            }
            builder.Append("\"first\"]}");

            return builder.ToString();
        }
    }
}

output is as follows:

Deserializing input of size 200001 to data contract enum took 3520 ms.
Deserializing input of size 200001 to simple enum took 1131 ms.

Are there any caching or other performance optimizations that I could enable to avoid the slowdown?


Solution

  • Performance of Enums with [EnumMember] should be improved with this commit and deserialization of Enums in this commit which utilizes cached enum info.

    This change is available from v5.4.1 that's now available on MyGet.