[转]序列化悍将protobuf-net,入门动手实录

zzz zzz     2022-08-01     587

关键词:

最近在研究web api 2,看了一篇文章,讲解如何提升性能的

在序列化速度的跑分中,Protobuf一骑绝尘,序列化速度快,性能强,体积小,所以打算了解下这个利器

 

1:安装篇

谷歌官方没有提供.net的实现,所以在nuget上找了一个移植的

Nuget里搜索Protobuf-net,下载,自动添加到项目中

 

2:定义数据结构 

复制代码
using ProtoBuf;

namespace ConsoleApplication1
{
    [ProtoContract]
    class Person
    {
        [ProtoMember(1)]
        public int Id { get; set; }
        [ProtoMember(2)]
        public string Name { get; set; }
        [ProtoMember(3)]
        public Address Address { get; set; }
    }
    [ProtoContract]
    class Address
    {
        [ProtoMember(1)]
        public string Line1 { get; set; }
        [ProtoMember(2)]
        public string Line2 { get; set; }
    }
}
复制代码

  

3:封装简单操作类

按照作者使用习惯,简单提供了一个Helper类

复制代码
using System.IO;
using System.Text;
using ProtoBuf;

namespace ConsoleApplication1
{
   public class ProtobufHelper
    {
       /// <summary>
       /// 序列化
       /// </summary>
       /// <typeparam name="T"></typeparam>
       /// <param name="t"></param>
       /// <returns></returns>
       public static string Serialize<T>(T t)
       {
           using (MemoryStream ms = new MemoryStream())
           {
               Serializer.Serialize<T>(ms, t);
               return Encoding.UTF8.GetString(ms.ToArray());
           }
       }

       /// <summary>
       /// 反序列化
       /// </summary>
       /// <typeparam name="T"></typeparam>
       /// <param name="content"></param>
       /// <returns></returns>
       public static T DeSerialize<T>(string content)
       {
           using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(content)))
           {
               T t = Serializer.Deserialize<T>(ms);
               return t;
           }
       }
    }
}
复制代码

 

4:操作体验

代码很简单,就不分开贴了

复制代码
using System;
using System.Collections.Generic;
using System.IO;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {

            var p1 = new Person
            {
                Id = 1,
                Name = "八百里开外",
                Address = new Address
                {
                    Line1 = "Line1",
                    Line2 = "Line2"
                }
            };

            var p2 = new Person
            {
                Id = 2,
                Name = "一枪",
                Address = new Address
                {
                    Line1 = "Flat Line1",
                    Line2 = "Flat Line2"
                }
            };

            List<Person> pSource = new List<Person>() { p1, p2 };

            string content = ProtobufHelper.Serialize<List<Person>>(pSource);

            Console.Write(content);
            //写入文件
            File.WriteAllText("D://hello.txt", content);
             


            Console.WriteLine("\r\n****解析部分*****");

            List<Person> pResult = ProtobufHelper.DeSerialize<List<Person>>(content);


            foreach (Person p in pResult)
            {
                Console.WriteLine(p.Name);
            }

            Console.Read();
        }
    }
}
复制代码

控制台运行结果

 

同样的数据,和Json所占用空间对比,高下立判

 

后记

protobuf虽然有千般好,但是我们是在 web api上使用的,前台js解析不了Protobuf,所以只能用Json咯~!

StackService虽然Github上有2K多个Star,但是收费的。。同样的事情web api 2也能做到,所以也略过它。

最终作者选择了跑分测试里面的第二名Jil  https://github.com/kevin-montrose/Jil

 

 


 

1. With very minimal annotation on the class level

[ProtoContract(ImplicitFields = ImplicitFields.AllPublic)] // only required on the class level
class PersonEntity
{
   public string FirstName { get; set; }
   public string LastName { get; set; }
}

 

2. Without any annotation (using RuntimeTypeModel)

static void InitializeProtobufRunTime()
{
    var assembly = Assembly.GetAssembly(typeof(PlainEntities.PersonEntity));
    var types = assembly.GetTypes();
    foreach (var t in types.Where(x => x.Namespace.Contains("PlainEntities")))
    {
        Console.WriteLine("Processing {0}", t.FullName);
        var meta = RuntimeTypeModel.Default.Add(t, false);
        var index = 1;

        // find any derived class for the entity
        foreach (var d in types.Where(x => x.IsSubclassOf(t)))
        {
            var i = index++;
            Console.WriteLine("\tSubtype: {0} - #{1}", d.Name, i);
            meta.AddSubType(i, d);
        }

        // then add the properties
        foreach (var p in t.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly).Where(x => x.GetSetMethod() != null))
        {
            var i = index++;
            Console.WriteLine("\tProperty: {0} - #{1}", p.Name, i);
            meta.AddField(i, p.Name);
        }
    }
}

 

And both the above works quite well without any performance differences.


------------------
TestBinaryEntities
------------------
Process: 100000 items, MemorySize: 7400705, Completed in: 3877 ms, Serialization took: 676 ms, Deserialization took: 2948 ms

----------------------------------
TestProtobufFullyAnnotatedEntities
----------------------------------
Process: 100000 items, MemorySize: 3983490, Completed in: 682 ms, Serialization took: 164 ms, Deserialization took: 253 ms

-------------------------------------
TestProtobufImplicitAnnotatedEntities
-------------------------------------
Process: 100000 items, MemorySize: 3983490, Completed in: 595 ms, Serialization took: 104 ms, Deserialization took: 210 ms

-------------------------------
TestProtobufRuntimeRegistration
-------------------------------
Processing ProtobufTestConsole.PlainEntities.BaseEntity
Subtype: PersonEntity - #1
Property: Id - #2
Property: Gender - #3
Processing ProtobufTestConsole.PlainEntities.PersonEntity
Property: FirstName - #1
Property: LastName - #2
Property: Age - #3
Process: 100000 items, MemorySize: 4083490, Completed in: 646 ms, Serialization took: 113 ms, Deserialization took: 232 ms

Looking forward to get this in :)

Also attached the sample project for reference

 

protobuf-net 序列化返回空数组

】protobuf-net序列化返回空数组【英文标题】:protobuf-netSerializationreturnsemptyarray【发布时间】:2013-02-0612:05:12【问题描述】:我使用“protobuf-net”序列化一个结构,但它返回一个空数组。publicstaticbyte[]PacketToArray(Packetpacket)IFormatterfo... 查看详情

使用 protobuf-net 序列化具有接口类型成员的类

】使用protobuf-net序列化具有接口类型成员的类【英文标题】:Serializeaclasshavinganinterfacetypememberusingprotobuf-net【发布时间】:2010-09-2323:50:40【问题描述】:我无法使用protobuf-net序列化我的类,问题似乎是protobuf-net无法序列化接口。i... 查看详情

Protobuf-Net:如何序列化 guid?

】Protobuf-Net:如何序列化guid?【英文标题】:Protobuf-Net:howtoserializeguids?【发布时间】:2010-08-3115:42:22【问题描述】:是否有在protobuf-net中序列化Guid的首选方法?它似乎不是受支持的类型?【问题讨论】:我一直将其序列化为字... 查看详情

protobuf-net 如何序列化 DateTime?

】protobuf-net如何序列化DateTime?【英文标题】:Howprotobuf-netserializeDateTime?【发布时间】:2014-06-0411:33:32【问题描述】:我正在开发一个由客户端/服务器组成的项目。客户端用Python编写(将在linux上运行),服务器用C#编写。我正... 查看详情

protobuf-net 对大文件进行反序列化

】protobuf-net对大文件进行反序列化【英文标题】:Bigfilesdeserializationsbyprotobuf-net【发布时间】:2013-01-0814:04:42【问题描述】:我需要反序列化1.5GB的txt文件。我正在使用来自code.google.com/p/protobuf-net/的protobuf-net有时它会在不同的地... 查看详情

序列化动态类型参数 Protobuf-net

】序列化动态类型参数Protobuf-net【英文标题】:SerializingdynamictypeparameterProtobuf-net【发布时间】:2013-12-3022:29:05【问题描述】:没有答案的可能重复:here和here。我正在尝试使用protobuf-net(2.0.0.668)序列化具有params对象数组的类。我... 查看详情

使用 protobuf-net 反序列化字典

】使用protobuf-net反序列化字典【英文标题】:DeserializeDictionarywithprotobuf-net【发布时间】:2015-03-1212:34:16【问题描述】:由于BinaryFormatter给我在Ios上序列化字典带来了麻烦,我决定切换到protobuf-net。并使用它来序列化我的Unity3d游... 查看详情

Protobuf-Net 总是反序列化一个空列表

】Protobuf-Net总是反序列化一个空列表【英文标题】:Protobuf-Netalwaysdeserializesanemptylist【发布时间】:2014-07-2111:21:54【问题描述】:以下代码显示了我如何尝试使用Protobuf-Net序列化/反序列化列表。方法getNewItem()返回一个ItemsStore的... 查看详情

protobuf-net 中通用集合的序列化

】protobuf-net中通用集合的序列化【英文标题】:Serializationofgenericcollectionsinprotobuf-net【发布时间】:2014-03-2709:16:22【问题描述】:我正在尝试使用protobuf-net序列化字典,但仍然得到“意外的子类型:”通用列表异常。这就是我构... 查看详情

Protobuf-net - 啥被序列化了?

】Protobuf-net-啥被序列化了?【英文标题】:Protobuf-net-whatwasserialized?Protobuf-net-什么被序列化了?【发布时间】:2012-11-2603:18:23【问题描述】:我正在尝试用Proto-buf替换我们现有的序列化。问题是我们目前使用ISerializable来检查数... 查看详情

protobuf-net:不正确的线型反序列化 TimeSpan

】protobuf-net:不正确的线型反序列化TimeSpan【英文标题】:protobuf-net:Incorrectwire-typedeserializingTimeSpan【发布时间】:2009-11-1219:41:34【问题描述】:当我的客户端应用程序尝试反序列化来自WCF服务的消息时(“不正确的线型反序列化... 查看详情

使用 Protobuf-Net 序列化未知子类型

】使用Protobuf-Net序列化未知子类型【英文标题】:SerializingUnknownSub-TypesWithProtobuf-Net【发布时间】:2021-09-0318:10:22【问题描述】:我目前正在尝试了解protobuf-net,并找到了这篇关于能够序列化子类型的文章:HowtoSerializeInheritedClassw... 查看详情

使用 protobuf-net 反序列化 int& 类型

】使用protobuf-net反序列化int&类型【英文标题】:Deserializingint&typewithprotobuf-net【发布时间】:2018-04-2713:01:15【问题描述】:我正在尝试升级旧代码库的依赖项以使用protobuf-net2.3.7而不是protobuf-net1.0以下代码用于版本1并打印21... 查看详情

protobuf-net 不比二进制序列化快吗?

】protobuf-net不比二进制序列化快吗?【英文标题】:protobuf-netNOTfasterthanbinaryserialization?【发布时间】:2010-06-0313:42:33【问题描述】:我编写了一个程序来使用XMLSerializer、BinaryFormatter和ProtoBuf序列化一个“Person”类。我认为protobuf-... 查看详情

protobuf-net 使用啥基本序列化器来输出字节数组?

】protobuf-net使用啥基本序列化器来输出字节数组?【英文标题】:Whatbaseserializerdoesprotobuf-netusetooutputbytearray?protobuf-net使用什么基本序列化器来输出字节数组?【发布时间】:2019-08-3003:13:28【问题描述】:protobuf-net是否使用BinaryFo... 查看详情

protobuf-net 反序列化错误 无效标签:0

】protobuf-net反序列化错误无效标签:0【英文标题】:protobuf-netdeserializingerrorInvalidtag:0【发布时间】:2011-06-0815:39:35【问题描述】:我想使用protobuf-net序列化字符串并反序列化回对象。如果我序列化到像.bin这样的文件,它工作正... 查看详情

NEventStore 3+ 的 Protobuf-net 序列化程序

】NEventStore3+的Protobuf-net序列化程序【英文标题】:Protobuf-netserializerforNEventStore3+【发布时间】:2013-04-0505:35:28【问题描述】:谁能给我指点NEventStore3.0的protobuf-net序列化程序?我认为主要是由于事件存储3中的序列化将事件主体和... 查看详情

protobuf-net:反序列化 Guid 属性的错误线型异常

】protobuf-net:反序列化Guid属性的错误线型异常【英文标题】:protobuf-net:incorrectwire-typeexceptiondeserializingGuidproperties【发布时间】:2010-04-1005:28:48【问题描述】:我在使用protobuf-net反序列化ORM生成的实体的某些Guid属性时遇到问题。... 查看详情