开发者

Serializing Guid[] to binary quickly to store in C# AppFabric

I am trying to read and write arrays of Guids to an AppFabric cache. My profiler shows me it is serializing this to Xml which means things are going far too slow. A Guid[20000] takes 60 ms to add to the cache whilst a similarly sized int[80000] takes 10 ms. I am figuring an array of Guids must surely look like a byte array somewhere intern开发者_StackOverflow社区ally. What is the fastest way to get to this, whilst generating as little meta-fluff as possible? I know where I will be adding and getting to/from the cache, and the data is not going to be particularly persistent, so I do not care about serializing class information.


I'd be surprised if the serialization used by the AppFabric cache used anything other than the binary writer from WCF, so if this is the case (which seems like it), then the difference is explained by the treatment of arrays in the binary format. Arrays for certain primitive types have a special node type which allows them to be stored very efficiently in the binary format. int (and byte) are some of those types. Guid is not (I don't know what the team chose to decide what would be an "array type" or not). So while serializing an array of integers in the binary format is very efficient, serializing an array of Guid is not.

As m0sa suggested, you can convert it to byte[] and you'll likely see a big improvement. I've found out that the LINQ syntax, although a lot cleaner, doesn't give you the big performance improvements you may get with a more traditional for loop. I've run the code below to compare the serialization speeds (which I think will map to the AF cache), and the serialization as byte[] (even with the conversion between the Guid[] to byte[]) is even faster than the one from the int[].

public class StackOverflow_6346646
{
    static void SerializeGuid()
    {
        Console.WriteLine("Serializing Guid[]");
        var guids = new Guid[20000];
        Random rndGen = new Random();
        for (int i = 0; i < guids.Length; i++)
        {
            guids[i] = Guid.NewGuid();
        }
        MemoryStream ms = new MemoryStream();
        Stopwatch watch = new Stopwatch();
        DataContractSerializer dcs = new DataContractSerializer(guids.GetType());
        XmlDictionaryWriter binaryWriter = XmlDictionaryWriter.CreateBinaryWriter(ms);
        watch.Start();
        dcs.WriteObject(binaryWriter, guids);
        binaryWriter.Flush();
        watch.Stop();
        Console.WriteLine("Serialized in {0}ms, total size = {1} bytes", watch.ElapsedMilliseconds, ms.Position);
    }
    static void SerializeInt()
    {
        Console.WriteLine("Serializing int[]");
        var guids = new int[80000]; // new Guid[20000];
        Random rndGen = new Random();
        for (int i = 0; i < guids.Length; i++)
        {
            guids[i] = rndGen.Next(); // Guid.NewGuid();
        }
        MemoryStream ms = new MemoryStream();
        Stopwatch watch = new Stopwatch();
        DataContractSerializer dcs = new DataContractSerializer(guids.GetType());
        XmlDictionaryWriter binaryWriter = XmlDictionaryWriter.CreateBinaryWriter(ms);
        watch.Start();
        dcs.WriteObject(binaryWriter, guids);
        binaryWriter.Flush();
        watch.Stop();
        Console.WriteLine("Serialized in {0}ms, total size = {1} bytes", watch.ElapsedMilliseconds, ms.Position);
    }
    static void SerializeGuidAsByteArray(bool useLinq)
    {
        Console.WriteLine("Serializing Guid[] as byte[], {0}", useLinq ? "using LINQ" : "not using LINQ");
        var guids = new Guid[20000];
        Random rndGen = new Random();
        for (int i = 0; i < guids.Length; i++)
        {
            guids[i] = Guid.NewGuid();
        }

        MemoryStream ms = new MemoryStream();
        Stopwatch watch = new Stopwatch();
        DataContractSerializer dcs = new DataContractSerializer(typeof(byte[]));
        XmlDictionaryWriter binaryWriter = XmlDictionaryWriter.CreateBinaryWriter(ms);
        watch.Start();
        byte[] bytes;
        if (useLinq)
        {
            bytes = guids.SelectMany(x => x.ToByteArray()).ToArray();
        }
        else
        {
            bytes = new byte[guids.Length * 16];
            for (int i = 0; i < guids.Length; i++)
            {
                byte[] guidBytes = guids[i].ToByteArray();
                Buffer.BlockCopy(guidBytes, 0, bytes, 16 * i, 16);
            }
        }
        dcs.WriteObject(binaryWriter, bytes);
        binaryWriter.Flush();
        watch.Stop();
        Console.WriteLine("Serialized in {0}ms, total size = {1} bytes", watch.ElapsedMilliseconds, ms.Position);
    }
    public static void Test()
    {
        SerializeGuid();
        SerializeInt();
        SerializeGuidAsByteArray(true);
        SerializeGuidAsByteArray(false);
    }
}


Use Guid.ToByteArray()

Guid[] yourArray = ...;
byte[][] serializedArray = yourArray.Select(x => x.ToByteArray()).ToArray();

You could even serialize it into a 1 dimensional array, since the length of the Guid byte array is known (16):

byte[] serializedArray = yourArray.SelectMany(x => x.ToByteArray()).ToArray();
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜