正在将Guid[]快速序列化为二进制文件以存储在C#AppFabric中

本文关键字:二进制文件 C#AppFabric 序列化 存储 Guid | 更新日期: 2023-09-27 17:59:19

我正在尝试将Guid的数组读写到AppFabric缓存中。我的探查器显示它正在将其序列化为Xml,这意味着事情进展得太慢了。一个Guid[20000]需要60毫秒才能添加到缓存中,而一个类似大小的int[80000]需要10毫秒。在生成尽可能少的元绒毛的同时,最快的方法是什么?我知道我将在哪里添加和从缓存中获取数据,而且数据不会特别持久,所以我不关心序列化类信息。

正在将Guid[]快速序列化为二进制文件以存储在C#AppFabric中

如果AppFabric缓存使用的序列化使用了WCF中的二进制编写器之外的任何东西,我会感到惊讶,所以如果是这样的话(看起来是这样),那么区别可以通过二进制格式中数组的处理来解释。某些基元类型的数组有一个特殊的节点类型,这使得它们可以非常有效地以二进制格式存储。int(和byte)就是其中的一些类型。Guid不是(我不知道团队选择了什么来决定什么是"数组类型")。因此,虽然以二进制格式序列化整数数组非常有效,但序列化Guid数组则不然。

正如m0sa所建议的,您可以将其转换为byte[],您可能会看到很大的改进。我发现LINQ语法虽然干净得多,但并没有给您带来更传统的for循环可能带来的巨大性能改进。我已经运行了下面的代码来比较序列化速度(我认为这将映射到AF缓存),并且作为byte[]的序列化(即使在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);
    }
}

使用Guid.ToByteArray()

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

您甚至可以将其序列化为一维数组,因为Guid字节数组的长度是已知的(16):

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