gpt4 book ai didi

protocol-buffers - 如何从 protobuf-net 中获得最大性能

转载 作者:行者123 更新时间:2023-12-04 14:41:25 27 4
gpt4 key购买 nike

我想使用 protobuf-net 序列化股市数据。我正在玩以下消息模型:

1st message: Meta Data describing what data to expect and some other info.
2nd message: DataBegin
3rd message: DataItem
4th message: DataItem
...
nth message: EndData

这是一个数据项的例子:

class Bar{
DateTime DateTime{get;set;}
float Open{get;set}
float High{get;set}
float Low{get;set}
float Close{get;set}
intVolume{get;set}
}

现在我正在使用 TypeModel.SerializeWithLengthPrefix(...) 来序列化每条消息(TypeModel 已编译)。效果很好,但比使用 BinaryWriter 手动序列化每条消息慢 10 倍左右。这里重要的当然不是元数据,而是每个 DataItem 的序列化。我有大量数据,在某些情况下,这些数据被读取/写入文件,性能至关重要。

提高每个 DataItem 的序列化和反序列化性能的好方法是什么?

我应该在这里直接使用 ProtoWriter 吗?如果是,我该怎么做(我对 Protocol Buffers 有点陌生)。

最佳答案

是的,如果您的数据是一组非常简单的同质记录,没有额外的要求(例如,它不需要向前兼容或版本优雅,或者可以从不完全了解所有内容的客户端使用数据),不需要方便可移植,并且您不介意手动实现所有序列化,那么是的:您可以更有效地手动完成。在快速测试中:

protobuf-net serialize: 55ms, 3581680 bytes
protobuf-net deserialize: 65ms, 100000 items
BinaryFormatter serialize: 443ms, 4200629 bytes
BinaryFormatter deserialize: 745ms, 100000 items
manual serialize: 26ms, 2800004 bytes
manual deserialize: 32ms, 100000 items

额外的空间大概是字段标记(如果您手动打包记录并且不需要担心同时使用不同版本的 API,则不需要它)。

我当然不会复制“10x”;我得到 2x,考虑到 protobuf 提供的东西,这还不错。而且肯定比 BinaryFormatter 好很多,后者大约是 20 倍!以下是一些功能:

  • 版本容错
  • 便携性
  • 架构使用
  • 没有手动代码
  • 对子对象和集合的内置支持
  • 支持省略默认值
  • 支持常见的 .NET 场景(序列化回调;条件序列化模式等)
  • 继承(仅限 protobuf-net;不是标准 protobuf 规范的一部分)

在您的场景中,听起来需要手动序列化;没关系 - 我没有被冒犯;p 序列化库的目的是以不需要手动编写代码的方式解决更普遍的问题

我的测试平台:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using ProtoBuf;
using ProtoBuf.Meta;
using System.Runtime.Serialization.Formatters.Binary;

public static class Program
{
static void Main()
{

var model = RuntimeTypeModel.Create();
model.Add(typeof(BarWrapper), true);
model.Add(typeof(Bar), true);
model.CompileInPlace();

var data = CreateBar(100000).ToList();
RunTest(model, data);

}

private static void RunTest(RuntimeTypeModel model, List<Bar> data)
{
using(var ms = new MemoryStream())
{
var watch = Stopwatch.StartNew();
model.Serialize(ms, new BarWrapper {Bars = data});
watch.Stop();
Console.WriteLine("protobuf-net serialize: {0}ms, {1} bytes", watch.ElapsedMilliseconds, ms.Length);

ms.Position = 0;
watch = Stopwatch.StartNew();
var bars = ((BarWrapper) model.Deserialize(ms, null, typeof (BarWrapper))).Bars;
watch.Stop();
Console.WriteLine("protobuf-net deserialize: {0}ms, {1} items", watch.ElapsedMilliseconds, bars.Count);
}
using (var ms = new MemoryStream())
{
var bf = new BinaryFormatter();
var watch = Stopwatch.StartNew();
bf.Serialize(ms, new BarWrapper { Bars = data });
watch.Stop();
Console.WriteLine("BinaryFormatter serialize: {0}ms, {1} bytes", watch.ElapsedMilliseconds, ms.Length);

ms.Position = 0;
watch = Stopwatch.StartNew();
var bars = ((BarWrapper)bf.Deserialize(ms)).Bars;
watch.Stop();
Console.WriteLine("BinaryFormatter deserialize: {0}ms, {1} items", watch.ElapsedMilliseconds, bars.Count);
}
byte[] raw;
using (var ms = new MemoryStream())
{
var watch = Stopwatch.StartNew();
WriteBars(ms, data);
watch.Stop();
raw = ms.ToArray();
Console.WriteLine("manual serialize: {0}ms, {1} bytes", watch.ElapsedMilliseconds, raw.Length);
}
using(var ms = new MemoryStream(raw))
{
var watch = Stopwatch.StartNew();
var bars = ReadBars(ms);
watch.Stop();
Console.WriteLine("manual deserialize: {0}ms, {1} items", watch.ElapsedMilliseconds, bars.Count);
}

}
static IList<Bar> ReadBars(Stream stream)
{
using(var reader = new BinaryReader(stream))
{
int count = reader.ReadInt32();
var bars = new List<Bar>(count);
while(count-- > 0)
{
var bar = new Bar();
bar.DateTime = DateTime.FromBinary(reader.ReadInt64());
bar.Open = reader.ReadInt32();
bar.High = reader.ReadInt32();
bar.Low = reader.ReadInt32();
bar.Close = reader.ReadInt32();
bar.Volume = reader.ReadInt32();
bars.Add(bar);
}
return bars;
}
}
static void WriteBars(Stream stream, IList<Bar> bars )
{
using(var writer = new BinaryWriter(stream))
{
writer.Write(bars.Count);
foreach (var bar in bars)
{
writer.Write(bar.DateTime.ToBinary());
writer.Write(bar.Open);
writer.Write(bar.High);
writer.Write(bar.Low);
writer.Write(bar.Close);
writer.Write(bar.Volume);
}
}

}
static IEnumerable<Bar> CreateBar(int count)
{
var rand = new Random(12345);
while(count-- > 0)
{
var bar = new Bar();
bar.DateTime = new DateTime(
rand.Next(2008,2011), rand.Next(1,13), rand.Next(1, 29),
rand.Next(0,24), rand.Next(0,60), rand.Next(0,60));
bar.Open = (float) rand.NextDouble();
bar.High = (float)rand.NextDouble();
bar.Low = (float)rand.NextDouble();
bar.Close = (float)rand.NextDouble();
bar.Volume = rand.Next(-50000, 50000);
yield return bar;
}
}

}
[ProtoContract]
[Serializable] // just for BinaryFormatter test
public class BarWrapper
{
[ProtoMember(1, DataFormat = DataFormat.Group)]
public List<Bar> Bars { get; set; }
}
[ProtoContract]
[Serializable] // just for BinaryFormatter test
public class Bar
{
[ProtoMember(1)]
public DateTime DateTime { get; set; }

[ProtoMember(2)]
public float Open { get; set; }

[ProtoMember(3)]
public float High { get; set; }

[ProtoMember(4)]
public float Low { get; set; }

[ProtoMember(5)]
public float Close { get; set; }

// use zigzag if it can be -ve/+ve, or default if non-negative only
[ProtoMember(6, DataFormat = DataFormat.ZigZag)]
public int Volume { get; set; }
}

关于protocol-buffers - 如何从 protobuf-net 中获得最大性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8329710/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com