Fala, galera!
Antes de começar o artigo, gostaria de compartilhar com vocês que tive a grande honra de me tornar MVP (Microsoft Most Valuable Professional). Com isso, poderei ajudar ainda mais a comunidade com meus artigos, eventos e etc. Deixo o meu muito obrigado a todos que ajudaram de alguma forma, lendo meus artigos, comentando ou indo a eventos nos quais eu ajudei a organizar.
Neste artigo irei falar de uma biblioteca chamada Protobuf.
Essa biblioteca é de extrema valia quando precisamos serializar uma grande quantidade de dados e com uma performance excepcional. Muitas das vezes fazer parse de JSON ou XML não é ideal quando estamos falando de objetos grandes com alguns megas de dados. Neste tipo de cenário uma serialização em formato binário é muito mais eficiente.
A biblioteca Protobuf tem algumas particularidades, como:
- [ProtoContract]: indica que a classe será serializada usando o Protobuf
- [ProtoMember]: indica que a propriedade/field deverá ser serializada usando o Protobuf
- [ProtoIgnore]: indica que a propriedade/field será ignorada quando uma serialização ocorrer
Outras características do Protobuf:
- A serialização do Protobuf ignora a interface ISerializable
- Não é possível customizar a serialização do Protobuf usando a interface ISerializable
Show me the code!
Para usar o Protobuf, basta instalar usando o Package Manager Console através do comando abaixo:
Install-Package protobuf-net
Para esse exemplo criei uma classe chamada Cliente e Endereço e anotei com os atributos do Protobuf, conforme no exemplo abaixo:
[ProtoContract()] public class Cliente { [ProtoMember(1)] public string PrimeroNome { get; set; } [ProtoMember(2)] public string UltimoNome { get; set; } [ProtoMember(3)] public DateTime DataNascimento { get; set; } [ProtoMember(4)] public List<Endereco> Enderecos { get; set; } } [ProtoContract()] public class Endereco { [ProtoMember(1)] public string Logradouro { get; set; } [ProtoMember(2)] public string Complemento { get; set; } [ProtoMember(3)] public string Bairro { get; set; } [ProtoMember(4)] public string Cidade { get; set; } [ProtoMember(5)] public string Pais { get; set; } }
Feito isso, criei uma classe estática que servirá para serializar e desserializar os objetos.
public static class ProtoSerialize { public static byte[] Serialize<T>(T obj) where T : class { if (obj == null) return new byte[] { }; using(var stream = new MemoryStream()) { ProtoBuf.Serializer.Serialize<T>(stream, obj); return stream.ToArray(); } } public static T Deserialize<T>(byte[] data) where T : class { if (data == null) return default(T); using (var stream = new MemoryStream(data)) { return ProtoBuf.Serializer.Deserialize<T>(stream); } } }
Para rodar nosso projeto eu criei um Console Application. Nele temos um teste de desempenho usando a biblioteca Newtonsoft.json, umas das mais famosas bibliotecas para se converter objetos C# em JSON.
static void Main(string[] args) { var stopWatch = Stopwatch.StartNew(); for (int i = 0; i < 5000000; i++) { var obj = CreateCliente(i); Newtonsoft.Json.JsonConvert.SerializeObject(obj); } stopWatch.Stop(); TimeSpan ts = stopWatch.Elapsed; string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10); Console.WriteLine("RunTime Json " + elapsedTime); var stopProto = Stopwatch.StartNew(); for (int i = 0; i < 5000000; i++) { var obj = CreateCliente(i); Protobuf.Serializer.ProtoSerialize.Serialize<Cliente>(obj); } stopProto.Stop(); TimeSpan tsProto = stopProto.Elapsed; string elapsedTimeProto = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", tsProto.Hours, tsProto.Minutes, tsProto.Seconds, tsProto.Milliseconds / 10); Console.WriteLine("RunTime Proto " + elapsedTimeProto); Console.Read(); } private static Cliente CreateCliente(int i) { return new Object.Cliente() { DataNascimento = DateTime.Now, PrimeroNome = quot;Cliente{i}", UltimoNome = quot;UltimoNome{i}", Enderecos = new List<Endereco>() { new Object.Endereco() { Bairro = quot;Bairro{i}", Cidade = quot;Cidade{i}", Complemento = quot;Complemento{i}", Logradouro = quot;Logradouro{i}", Pais = quot;Pais{i}" } } }; }
A velocidade de serialização dos objetos usando o Protobuf chega a ser 17s mais rápido em relação ao Newtonsoft.json.
Abaixo uma gráfico de comparação de performance em relação a outras bibliotecas.
O código deste artigo está no meu GitHub; você pode acessá-lo clicando aqui.
A documentação do Protobuf pode se encontrada neste link.
Abraços e até a próxima!