Ben*_*Ben 12 .net c# performance wcf wcf-binding
我有以下对象:
public partial class Game
{
public bool Finished { get; set; }
public Guid GameGUID { get; set; }
public long GameID { get; set; }
public bool GameSetup { get; set; }
public Nullable<int> MaximumCardsInDeck { get; set; }
public Player Player { get; set; }
public Player Player1 { get; set; }
public bool Player1Connected { get; set; }
public bool Player1EnvironmentSetup { get; set; }
public long Player1ID { get; set; }
public int Player1Won { get; set; }
public bool Player2Connected { get; set; }
public bool Player2EnvironmentSetup { get; set; }
public long Player2ID { get; set; }
public int Player2Won { get; set; }
public int Round { get; set; }
public Nullable<int> RoundsToWin { get; set; }
public bool Started { get; set; }
public string StateXML { get; set; }
public Nullable<DateTime> TimeEnded { get; set; }
public Nullable<int> TimeLimitPerTurn { get; set; }
public byte[] TimeStamp { get; set; }
public Nullable<DateTime> TimeStarted { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
这个课程将填充一些测试数据.
我需要比较WCF服务的不同形式的绑定所使用的不同Serializer 的性能:
我需要做的是:
我已经尝试了一些东西,但我有点挣扎.也许已经有一些简单的代码用于这种测量.
Mar*_*ell 35
好; 我会咬一口......这里有一些原始的串行器指标(例如:你可能需要考虑base-64/MTOM来获得总体带宽需求,加上WCF添加的固定开销(空间和CPU)); 结果第一:
BinaryFormatter
Length: 1314
Serialize: 6746
Deserialize: 6268
XmlSerializer
Length: 1049
Serialize: 3282
Deserialize: 5132
DataContractSerializer
Length: 911
Serialize: 1411
Deserialize: 4380
NetDataContractSerializer
Length: 1139
Serialize: 2014
Deserialize: 5645
JavaScriptSerializer
Length: 528
Serialize: 12050
Deserialize: 30558
(protobuf-net v2)
Length: 112
Serialize: 217
Deserialize: 250
Run Code Online (Sandbox Code Playgroud)
(所以我总结protobuf-net v2获胜者......)
在较新的机器上使用.NET 4.5和当前库构建更新的数字:
BinaryFormatter
Length: 1313
Serialize: 2786
Deserialize: 2407
XmlSerializer
Length: 1049
Serialize: 1265
Deserialize: 2165
DataContractSerializer
Length: 911
Serialize: 574
Deserialize: 2011
NetDataContractSerializer
Length: 1138
Serialize: 850
Deserialize: 2535
JavaScriptSerializer
Length: 528
Serialize: 8660
Deserialize: 8468
(protobuf-net v2)
Length: 112
Serialize: 78
Deserialize: 134
Run Code Online (Sandbox Code Playgroud)
使用测试装备(使用优化编译,在命令行运行):
(并注意我必须发明Player
类和一些示例数据):
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Web.Script.Serialization;
using System.Xml.Serialization;
using ProtoBuf.Meta;
static class Program
{
static void Main()
{
var orig = new Game {
Finished = true, GameGUID = Guid.NewGuid(), GameID = 12345, GameSetup = false, MaximumCardsInDeck = 20,
Player = new Player { Name = "Fred"}, Player1 = new Player { Name = "Barney"}, Player1Connected = true,
Player1EnvironmentSetup = true, Player1ID = 12345, Player1Won = 3, Player2Connected = true, Player2EnvironmentSetup = true,
Player2ID = 23456, Player2Won = 0, Round = 4, RoundsToWin = 5, Started = true, StateXML = "not really xml",
TimeEnded = null, TimeLimitPerTurn = 500, TimeStamp = new byte[] {1,2,3,4,5,6}, TimeStarted = DateTime.Today};
const int LOOP = 50000;
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
GC.WaitForPendingFinalizers();
using (var ms = new MemoryStream())
{
var ser = new BinaryFormatter();
Console.WriteLine();
Console.WriteLine(ser.GetType().Name);
ser.Serialize(ms, orig);
Console.WriteLine("Length: " + ms.Length);
ms.Position = 0;
ser.Deserialize(ms);
var watch = Stopwatch.StartNew();
for (int i = 0; i < LOOP; i++)
{
ms.Position = 0;
ms.SetLength(0);
ser.Serialize(ms, orig);
}
watch.Stop();
Console.WriteLine("Serialize: " + watch.ElapsedMilliseconds);
watch = Stopwatch.StartNew();
for (int i = 0; i < LOOP; i++)
{
ms.Position = 0;
ser.Deserialize(ms);
}
watch.Stop();
Console.WriteLine("Deserialize: " + watch.ElapsedMilliseconds);
}
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
GC.WaitForPendingFinalizers();
using (var ms = new MemoryStream())
{
var ser = new XmlSerializer(typeof(Game));
Console.WriteLine();
Console.WriteLine(ser.GetType().Name);
ser.Serialize(ms, orig);
Console.WriteLine("Length: " + ms.Length);
ms.Position = 0;
ser.Deserialize(ms);
var watch = Stopwatch.StartNew();
for (int i = 0; i < LOOP; i++)
{
ms.Position = 0;
ms.SetLength(0);
ser.Serialize(ms, orig);
}
watch.Stop();
Console.WriteLine("Serialize: " + watch.ElapsedMilliseconds);
watch = Stopwatch.StartNew();
for (int i = 0; i < LOOP; i++)
{
ms.Position = 0;
ser.Deserialize(ms);
}
watch.Stop();
Console.WriteLine("Deserialize: " + watch.ElapsedMilliseconds);
}
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
GC.WaitForPendingFinalizers();
using (var ms = new MemoryStream())
{
var ser = new DataContractSerializer(typeof(Game));
Console.WriteLine();
Console.WriteLine(ser.GetType().Name);
ser.WriteObject(ms, orig);
Console.WriteLine("Length: " + ms.Length);
ms.Position = 0;
ser.ReadObject(ms);
var watch = Stopwatch.StartNew();
for (int i = 0; i < LOOP; i++)
{
ms.Position = 0;
ms.SetLength(0);
ser.WriteObject(ms, orig);
}
watch.Stop();
Console.WriteLine("Serialize: " + watch.ElapsedMilliseconds);
watch = Stopwatch.StartNew();
for (int i = 0; i < LOOP; i++)
{
ms.Position = 0;
ser.ReadObject(ms);
}
watch.Stop();
Console.WriteLine("Deserialize: " + watch.ElapsedMilliseconds);
}
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
GC.WaitForPendingFinalizers();
using (var ms = new MemoryStream())
{
var ser = new NetDataContractSerializer();
Console.WriteLine();
Console.WriteLine(ser.GetType().Name);
ser.Serialize(ms, orig);
Console.WriteLine("Length: " + ms.Length);
ms.Position = 0;
ser.Deserialize(ms);
var watch = Stopwatch.StartNew();
for (int i = 0; i < LOOP; i++)
{
ms.Position = 0;
ms.SetLength(0);
ser.Serialize(ms, orig);
}
watch.Stop();
Console.WriteLine("Serialize: " + watch.ElapsedMilliseconds);
watch = Stopwatch.StartNew();
for (int i = 0; i < LOOP; i++)
{
ms.Position = 0;
ser.Deserialize(ms);
}
watch.Stop();
Console.WriteLine("Deserialize: " + watch.ElapsedMilliseconds);
}
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
GC.WaitForPendingFinalizers();
{
var sb = new StringBuilder();
var ser = new JavaScriptSerializer();
Console.WriteLine();
Console.WriteLine(ser.GetType().Name);
ser.Serialize(orig, sb);
Console.WriteLine("Length: " + sb.Length);
ser.Deserialize(sb.ToString(), typeof(Game));
var watch = Stopwatch.StartNew();
for (int i = 0; i < LOOP; i++)
{
sb.Length = 0;
ser.Serialize(orig, sb);
}
watch.Stop();
string s = sb.ToString();
Console.WriteLine("Serialize: " + watch.ElapsedMilliseconds);
watch = Stopwatch.StartNew();
for (int i = 0; i < LOOP; i++)
{
ser.Deserialize(s, typeof(Game));
}
watch.Stop();
Console.WriteLine("Deserialize: " + watch.ElapsedMilliseconds);
}
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
GC.WaitForPendingFinalizers();
using (var ms = new MemoryStream())
{
var ser = CreateProto();
Console.WriteLine();
Console.WriteLine("(protobuf-net v2)");
ser.Serialize(ms, orig);
Console.WriteLine("Length: " + ms.Length);
ms.Position = 0;
ser.Deserialize(ms, null, typeof(Game));
var watch = Stopwatch.StartNew();
for (int i = 0; i < LOOP; i++)
{
ms.Position = 0;
ms.SetLength(0);
ser.Serialize(ms, orig);
}
watch.Stop();
Console.WriteLine("Serialize: " + watch.ElapsedMilliseconds);
watch = Stopwatch.StartNew();
for (int i = 0; i < LOOP; i++)
{
ms.Position = 0;
ser.Deserialize(ms, null, typeof(Game));
}
watch.Stop();
Console.WriteLine("Deserialize: " + watch.ElapsedMilliseconds);
}
Console.WriteLine();
Console.WriteLine("All done; any key to exit");
Console.ReadKey();
}
static TypeModel CreateProto()
{
var meta = TypeModel.Create();
meta.Add(typeof(Game), false).Add(Array.ConvertAll(typeof(Game).GetProperties(),prop=>prop.Name));
meta.Add(typeof(Player), false).Add(Array.ConvertAll(typeof(Player).GetProperties(),prop=>prop.Name));
return meta.Compile();
}
}
[Serializable, DataContract]
public partial class Game
{
[DataMember]
public bool Finished { get; set; }
[DataMember]
public Guid GameGUID { get; set; }
[DataMember]
public long GameID { get; set; }
[DataMember]
public bool GameSetup { get; set; }
[DataMember]
public Nullable<int> MaximumCardsInDeck { get; set; }
[DataMember]
public Player Player { get; set; }
[DataMember]
public Player Player1 { get; set; }
[DataMember]
public bool Player1Connected { get; set; }
[DataMember]
public bool Player1EnvironmentSetup { get; set; }
[DataMember]
public long Player1ID { get; set; }
[DataMember]
public int Player1Won { get; set; }
[DataMember]
public bool Player2Connected { get; set; }
[DataMember]
public bool Player2EnvironmentSetup { get; set; }
[DataMember]
public long Player2ID { get; set; }
[DataMember]
public int Player2Won { get; set; }
[DataMember]
public int Round { get; set; }
[DataMember]
public Nullable<int> RoundsToWin { get; set; }
[DataMember]
public bool Started { get; set; }
[DataMember]
public string StateXML { get; set; }
[DataMember]
public Nullable<DateTime> TimeEnded { get; set; }
[DataMember]
public Nullable<int> TimeLimitPerTurn { get; set; }
[DataMember]
public byte[] TimeStamp { get; set; }
[DataMember]
public Nullable<DateTime> TimeStarted { get; set; }
}
[Serializable, DataContract]
public class Player
{
[DataMember]
public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
myt*_*thz 20
我还为.NET中的不同序列化器提供了基准测试图,显示@Marc Gravell的二进制protobuf-net序列化器作为明显的赢家.虽然我维护最快的文本序列化程序.NET,它最接近匹配它,并且比.NET中的BCL中的所有序列化程序快得多.
这些基准测试基于Microsoft的Nortwind示例数据库,并显示每个序列化程序与Protobuf-net的比较慢.
ProtoBuf.net(v1) 1x
ServiceStack TypeSerializer 2.23x
ServiceStack JsonSerializer 2.58x
Microsoft DataContractSerializer 6.93x
NewtonSoft.Json 7.83x
Microsoft BinaryFormatter 9.21x
Microsoft JsonDataContractSerializer 9.31x
Run Code Online (Sandbox Code Playgroud)
完整的基准测试可在此处获得
因此,如果您更喜欢/需要使用快速文本序列化器,则可以链接到Service Stack的开源文本序列化器:
顺便说一句,微软的JavaScriptSerializer表现出最差的性能,有时比protobuf-net低40到100倍.拿出来因为他们放慢了我的基准测试:)
我修改了@ Marc的基准源代码,并为ServiceStack的JSV和JSON Serializers添加了结果以下是我3yo iMac上的结果:
BinaryFormatter
Length: 1313
Serialize: 3959
Deserialize: 3395
XmlSerializer
Length: 1049
Serialize: 1710
Deserialize: 2716
DataContractSerializer
Length: 911
Serialize: 712
Deserialize: 2117
NetDataContractSerializer
Length: 1138
Serialize: 1093
Deserialize: 4825
TypeSerializer
Length: 431
Serialize: 496
Deserialize: 887
JsonSerializer
Length: 507
Serialize: 558
Deserialize: 1213
Run Code Online (Sandbox Code Playgroud)
以下是我在@ Marc的基准测试中添加的源代码.
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
GC.WaitForPendingFinalizers();
var sbJsv = new StringBuilder(4096);
using (var sw = new StringWriter(sbJsv))
{
Console.WriteLine();
Console.WriteLine(typeof(TypeSerializer).Name);
TypeSerializer.SerializeToWriter(orig, sw);
var jsv = sbJsv.ToString();
Console.WriteLine("Length: " + sbJsv.Length);
TypeSerializer.DeserializeFromString<Game>(jsv);
var watch = Stopwatch.StartNew();
for (int i = 0; i < LOOP; i++)
{
sbJsv.Length = 0;
TypeSerializer.SerializeToWriter(orig, sw);
}
watch.Stop();
Console.WriteLine("Serialize: " + watch.ElapsedMilliseconds);
watch = Stopwatch.StartNew();
for (int i = 0; i < LOOP; i++)
{
TypeSerializer.DeserializeFromString<Game>(jsv);
}
watch.Stop();
Console.WriteLine("Deserialize: " + watch.ElapsedMilliseconds);
}
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
GC.WaitForPendingFinalizers();
var sbJson = new StringBuilder(4096);
using (var sw = new StringWriter(sbJson))
{
Console.WriteLine();
Console.WriteLine(typeof(JsonSerializer).Name);
JsonSerializer.SerializeToWriter(orig, sw);
var json = sbJson.ToString();
Console.WriteLine("Length: " + sbJson.Length);
JsonSerializer.DeserializeFromString<Game>(json);
var watch = Stopwatch.StartNew();
for (int i = 0; i < LOOP; i++)
{
sbJson.Length = 0;
JsonSerializer.SerializeToWriter(orig, sw);
}
watch.Stop();
Console.WriteLine("Serialize: " + watch.ElapsedMilliseconds);
watch = Stopwatch.StartNew();
for (int i = 0; i < LOOP; i++)
{
JsonSerializer.DeserializeFromString<Game>(json);
}
watch.Stop();
Console.WriteLine("Deserialize: " + watch.ElapsedMilliseconds);
}
Run Code Online (Sandbox Code Playgroud)
注意:我无法得到他用于此的@ Marc的protobuf-net v2 r352 dll,所以我不得不评论protobuf-net基准测试.