Performance of protobuf-net vs DataContractSerializer over WCF
I tested protobuf serialization and it seems that for below a certain quantity of objects, it's slower than regular datacontract serialization. The transmission size is bigger using DataContractSerializer but during serialization and deserialization it is faster to use DataContractSerializer
Do you think this is normal or did I made a mistake?
[DataContract]
public partial class Toto
{
[DataMember]
public string NomToto { get; set; }
[DataMember]
public string PrenomToto { get; set; }
}
here is my class for datacontract this is the same for protobuf
[ProtoContract]
public partial class Titi
{
[ProtoMember(1)]
public string NomTiti { get; set; }
[ProtoMember(2)]
public string PrenomTiti { get; set; }
}
here's my methods for WCF services with protobuf (same for datacontract without ms )
public class TitiService : ITitiService
{
public byte[] GetAllTitis()
{
List<Titi> titiList = new List<Titi>();
for (int i = 0; i < 20000; i++)
{
var titi = new Titi
{
NomTiti = "NomTiti" + i,
PrenomTiti = "PrenomTiti" + i
};
titiList.Add(titi);
}
var ms = new MemoryStream();
Serializer.Serialize(ms, titiList);
byte[] arr = ms.ToArray();
return arr;
}
}
The service with datacontract
public class TotoService : ITotoService
{
public List<Toto> GetAllTotos()
{
开发者_JAVA百科 List<Toto> totoList = new List<Toto>();
for (int i = 0; i<20000; i++)
{
var toto = new Toto
{
NomToto = "NomToto" + i,
PrenomToto = "PrenomToto" + i
};
totoList.Add(toto);
}
return totoList;
}
}
here is the client call
public partial class Program
{
static ProtobufTestAzure.Client.TitiService.TitiServiceClient TitiClient;
static ProtobufTestAzure.Client.TotoService.TotoServiceClient TotoClient;
public static void Main(string[] args)
{
Stopwatch stopwatch1 = new Stopwatch();
Stopwatch stopwatch2 = new Stopwatch();
Stopwatch stopwatch3 = new Stopwatch();
stopwatch1.Start();
TitiClient = new ProtobufTestAzure.Client.TitiService.TitiServiceClient();
Byte[] titiByte = TitiClient.GetAllTitis();
TitiClient.Close();
stopwatch1.Stop();
stopwatch2.Start();
var ms = new MemoryStream(titiByte);
List<Titi> TitiList = Serializer.Deserialize<List<Titi>>(ms);
stopwatch2.Stop();
Console.WriteLine(" ");
stopwatch3.Start();
TotoClient = new ProtobufTestAzure.Client.TotoService.TotoServiceClient();
var TotoList = TotoClient.GetAllTotos();
TotoClient.Close();
stopwatch3.Stop();
Console.WriteLine("Time elapse for reception (Protobuf): {0} ms ({1} éléments)", stopwatch1.ElapsedMilliseconds, TitiList.Count);
Console.WriteLine("Time elapse for deserialization (Protobuf : {0} ms ({1} éléments)", stopwatch2.ElapsedMilliseconds, TitiList.Count);
Console.WriteLine("Time elapse for réception (Datacontract Serialization) : {0} ms ({1} éléments)", stopwatch3.ElapsedMilliseconds, TotoList.Count);
Console.ReadLine();
}
}
and the result for 10000 objects
Time elapse for reception (Protobuf): 3359 ms (10000 elements) Time elapse for deserialization (Protobuf): 138 ms (10000 elements) Time elapse for reception (Datacontract Serialization): 2200ms (10000 elements)
I test it whith 20000 objects It gave me for the first call
Time elapse for reception (Protobuf): 11258ms (20000 elements) Time elapse for deserialization (Protobuf): 133ms (20000 elements) Time elapse for reception (Datacontract Serialization): 3726ms (20000 elements)
for the second call
Time elapse for reception (Protobuf): 2844 ms (20000 elements) Time elapse for deserialization (Protobuf): 141 ms (20000 elements) Time elapse for reception (Datacontract Serialization): 7541 ms (20000 elements)
for the third
Time elapse for reception (Protobuf): 2767ms (20000 elements) Time elapse for deserialization (Protobuf): 145 ms (20000 elements) Time elapse for reception (Datacontract Serialization): 3989 ms (20000 elements)
After MTOM activation on 'Protobuf transfert' it gaves me:
for first call
Time elapse for reception (Protobuf): 3316 ms (20000 elements) Time elapse for deserialization (Protobuf): 63 ms (20000 elements) Time elapse for reception (Datacontract Serialization): 3769 ms (20000 elements)
for second call
Time elapse for reception (Protobuf): 2279 ms (20000 elements) Time elapse for deserialization (Protobuf): 57 ms (20000 elements) Time elapse for reception (Datacontract Serialization): 3959 ms (20000 elements)
I add this part of code for objects size
long totoSize = new long();
using (Stream s = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(s, totoList);
totoSize = s.Length;
}
long titiSize = titiByte.Count();
it gave me 637780 with protobuf and 1038236 with DataContractSerializer Durations for call are better and more stable this morning first call protobuf = 2498 ms datacontract = 5085 ms
second call protobuf = 3649 ms datacontract = 3840 ms
third call protobuf = 2498 ms datacontract = 5085 ms
Some factors that impact performance:
- is the serializer prepared? This is automatic on the first use per-type; the first time through, it needs to do quite a bit of inspection etc to figure out how your model works. You can offset this by calling
Serializer.PrepareSerializer<YourType>()
somewhere during startup- or as an alternative, in v2 (available as "alpha") you can pre-generate the serializer as a dll if you need the fastest possible cold-start performance
- what is the transport? in particular with WCF, you need to keep in mind how your
byte[]
is encoded (this isn't a problem on sockets, of course); for example, can the transport use MTOM? or is it base-64 encoding thebyte[]
?- and note also that it is possible that
Stream
andbyte[]
are handled differently; if you can measure the bandwidth, you might want to try both - basic-http with MTOM enabled is my preference for WCF transports if absolute speed is your aim; or sockets if you want to get closer to the limit
- and note also that it is possible that
精彩评论