Сериализация Guid [] в двоичном виде для быстрого хранения в C # AppFabric - PullRequest
4 голосов
/ 14 июня 2011

Я пытаюсь читать и записывать массивы Guids в кэш AppFabric.Мой профилировщик показывает мне, что он сериализует это в XML, что означает, что дела идут слишком медленно.Guid[20000] занимает 60 мс для добавления в кэш, в то время как int[80000] аналогичного размера занимает 10 мс.Я полагаю, что массив Guids должен выглядеть как байтовый массив где-то внутри.Какой самый быстрый способ добраться до этого, при этом генерируя как можно меньше мета-пуха?Я знаю, куда я буду добавлять и получать данные из кэша, и данные не будут особенно постоянными, поэтому мне нет дела до сериализации информации о классе.

Ответы [ 2 ]

4 голосов
/ 14 июня 2011

Я был бы удивлен, если бы в сериализации, используемой кешем AppFabric, использовалось что-то кроме двоичного средства записи из WCF, поэтому, если это так (как это выглядит), то разница объясняется обработкой массивов в двоичный формат. Массивы для определенных типов примитивов имеют специальный тип узла , который позволяет очень эффективно хранить их в двоичном формате. int (и byte) - некоторые из этих типов. Guid нет (я не знаю, что команда выбрала, чтобы решить, будет ли это «тип массива» или нет). Так что, хотя сериализация массива целых чисел в двоичном формате очень эффективна, сериализация массива Guid - нет.

Как предложил m0sa, вы можете преобразовать его в байт [], и вы, вероятно, увидите значительное улучшение. Я обнаружил, что синтаксис LINQ, хотя и намного чище, не дает вам больших улучшений производительности, которые вы можете получить с более традиционным циклом for. Я запустил приведенный ниже код для сравнения скоростей сериализации (которые, я думаю, будут отображаться в кэш AF), и сериализация в виде байта [] (даже с преобразованием между Guid [] в byte []) даже быстрее, чем тот из 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);
    }
}
2 голосов
/ 14 июня 2011

Использовать Guid. ToByteArray ()

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

Можно даже сериализовать его в одномерный массив, поскольку длина байтового массива Guid известна (16):

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