首页 > 代码库 > [转]序列化悍将Protobuf-Net,入门动手实录

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

最近在研究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 levelclass 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,入门动手实录