Google Protocol Buffers – Voando baixo com serializações utilizando o Protobuf-net

Sempre estamos serializando ou deserializando algum objeto, manualmente ou deixando o framework fazer o trabalho “sujo”, não podemos esquecer que isso tem um custo, dependendo do tipo de serialização que escolhemos esse custo pode ser muito alto.

E para nossa alegria o Google sabe isso, e ele criou o Google Protocol Buffers, é simples e rápido, na verdade muito rápido!!! Recomendo a leitura da documentação para entender o funcionamento do Protocol Buffers.

Uma descrição rápida do Protocol Buffers.

protocol buffers is the name of the binary serialization format used by Google for much of their data communications. It is designed to be:

small in size – efficient data storage (far smaller than xml) cheap to process – both at the client and server platform independent – portable between different programming architectures extensible – to add new data to old messages

Já que o Google mostrou pra todo mundo como fazer, uma implementação do Protocol Buffers foi criada em .net, chamada Protobuf-net, ela funciona com praticamente todas as versões do .NET, suporta Silverlight, Mono e está no Google Code, então quem quiser pode ajudar no projeto! ;)

Serializar e deserializar objetos com o Protobuf-net é simples, então não vou ficar mostrando exemplos, mas vou colocar um teste de desempenho que fiz para comparar alguns tipos de serializações nativas do .NET contra o Protobuf-net.

A idéia do teste é simples, vou adicionar em uma lista de Albuns 100.000 albuns, a primeira parte que consistem em serializar vou percorrer essa lista e criar uma nova lista de byte[] com cada album serializado, e a parte da deserialização percorro a lista com byte[] da serialização e crio uma nova lista com Albuns.

A classe Album é simples, e está marcada com nossos conhecidos atributos de serialização e de contratos.

[Serializable]
[DataContract]
public class Album
{
    [DataMember]
    public string Titulo { get; set; }
    [DataMember]
    public int AnoDeLancamento { get; set; }
}

E agora o código que cria a lista com os albuns que serão serializados.

private const int TotalDeAlbuns = 100000;
private static readonly List Albuns = Enumerable.Range(0, TotalDeAlbuns).Select(x => CriarAlbum(x)).ToList(); 

private static Album CriarAlbum(int numeroDoAlbum)
{
    return new Album {AnoDeLancamento = numeroDoAlbum, Titulo = numeroDoAlbum.ToString()};
}

Eu fiz os testes utilizando as seguintes formatos de serialização:

[list_blue]

  • Protobuf-net
  • BinaryFormatter
  • DataContractSerializer
  • XmlSerializer

[/list_blue]

E agora finalmente os códigos, são iguais só alterando o formato da serialização.

[tabs]

[/tabs]

Execute a aplicação 3 vezes, em Release, segue o gráfico com a média de tempo de cada formato de serialização. E o Protobuf-net realmente da um show.

É interessante analisar esses tempos, o XmlSerializer é muito lento, e o DataContractSerializer manda bem para serializar, mas para deserializar não é tão bom.

É importante ver que mesmo com o .NET disponibilizando vários formatos de serialização, precisamos sair da “zona de conforto” e buscar melhores alternativas, é claro que isso depende do cenário de cada um, mas caso esteja atendendo cenários críticos onde qualquer segundo faz diferença é sempre bom abrir a cabeça e aceitar novidades ;).

O código fonte do projeto está no github.

Abraços.