为啥我的代码中的 protobuf-net 反序列化器比流式读取 csv 慢得多

Posted

技术标签:

【中文标题】为啥我的代码中的 protobuf-net 反序列化器比流式读取 csv 慢得多【英文标题】:Why is protobuf-net deserializer so much slower in my code than streamreading csv为什么我的代码中的 protobuf-net 反序列化器比流式读取 csv 慢得多 【发布时间】:2012-01-31 15:25:03 【问题描述】:

我以以下格式存储简单的时间序列,并寻找最快的方式来读取和解析它们以“引用”对象:

日期时间,价格 1,价格 2 . . . DateTime 采用以下字符串格式:YYYYmmdd HH:mm:ss:fff price1 和 price 2 是小数点后 5 位的数字字符串(即 1.40505)

我尝试了不同的方式来存储和读取数据,还玩弄了 protobuf-net 库。已序列化并包含大约 600 万行的文件(原始 csv 按以下方式序列化:

TimeSeries 对象,持有List<Blobs>, 包含 Header 对象和 List<Quotes> 的 Blob 对象(一个 Blob 包含一天的引号) 引用包含 DateTime、双 px1 和双 px2 的对象

从磁盘读取(从磁盘)序列化的二进制文件并反序列化它花了大约 47 秒,这看起来非常长。相比之下,我将时间序列保存为 csv 字符串格式,将每一行读入一个列表,然后将每一行解析为 DateTime dt、双 px1、双 px1,我将其插入新创建的 Quote 对象并将它们添加到列表中。 读取大约需要 10 秒(使用 GZip 压缩需要 12 秒 -> 使文件大小约为 1/9。)

乍一看,我要么错误地处理了 protobuf-net 功能,要么这种特殊的时间序列不适合序列化/反序列化。

任何 cmets 或帮助,尤其是 Marc,如果你读到这里,你能插话并添加一些你的想法吗?我很难想象我最终会得到如此不同的性能数字。

一些信息:我不需要随机访问数据。我只需要阅读一整天,因此将一天的数据存储在一个单独的 csv 文件中对我的目的来说是有意义的,我想。

任何想法可能是读取此类数据的最快方法?我为这种简单化的语言道歉,我不是一个程序员

这是我用于 protobuf-net 的示例对象:

[ProtoContract]
class TimeSeries

    [ProtoMember(1)]
    public Header Header  get; set; 
    [ProtoMember(2)]
    public List<DataBlob> DataBlobs  get; set; 


[ProtoContract]
class DataBlob

    [ProtoMember(1)]
    public Header Header  get; set; 
    [ProtoMember(2)]
    public List<Quote> Quotes  get; set; 


[ProtoContract]
class Header

    [ProtoMember(1)]
    public string SymbolID  get; set; 
    [ProtoMember(2)]
    public DateTime StartDateTime  get; set; 
    [ProtoMember(3)]
    public DateTime EndDateTime  get; set; 


[ProtoContract]
class Quote

    [ProtoMember(1)]
    public DateTime DateTime  get; set; 
    [ProtoMember(2)]
    public double BidPrice  get; set; 
    [ProtoMember(3)]
    public long AskPrice  get; set;  //Expressed as Spread to BidPrice

这是用于序列化/反序列化的代码:

public static void SerializeAll(string fileNameWrite, List<Quote> QuoteList)
    
        //Header
        Header Header = new Header();
        Header.SymbolID = SymbolID;
        Header.StartDateTime = StartDateTime;
        Header.EndDateTime = EndDateTime;

        //Blob
        List<DataBlob> DataBlobs = new List<DataBlob>();
        DataBlob DataBlob = new DataBlob();
        DataBlob.Header = Header;
        DataBlob.Quotes = QuoteList;
        DataBlobs.Add(DataBlob);

        //Create TimeSeries
        TimeSeries TimeSeries = new TimeSeries();
        TimeSeries.Header = Header;
        TimeSeries.DataBlobs = DataBlobs;

        using (var file = File.Create(fileNameWrite))
        
            Serializer.Serialize(file, TimeSeries);
        
    

public static TimeSeries DeserializeAll(string fileNameBinRead)
    
        TimeSeries TimeSeries;

        using (var file = File.OpenRead(fileNameBinRead))
        
            TimeSeries = Serializer.Deserialize<TimeSeries>(file);
        

        return TimeSeries;
    

【问题讨论】:

如果您发布代码片段会有所帮助,以便人们可以查看您的代码中是否存在一些逻辑错误。 嗨,马特,如果您发布代码示例或链接到在 pastebin 上重现该问题的解决方案,您可能会发现您会得到更好的响应。最好的问候, 谢谢,添加了我在 protobuf-net 中用于序列化/反序列化目的的示例对象。我知道 AskPrice 可以调整为短......但我认为为了与其他方法进行比较,它不会太重要,因为我喜欢最终得到一个“TimeSeries”对象 有没有机会进行更多的测试,以便我给出准确的答案? @Marc,感谢您提供查看,我添加了序列化和反序列化部分。 【参考方案1】:

最快的方法是手动编码的二进制序列化器,特别是如果您转换 pices 滴答声。这就是我所做的,尽管我的交易量略有不同(每天 6 亿个项目,大约 200.000 个符号,其中一些是头重脚轻的)。我没有以需要从文本解析的方式存储任何内容。解析器是手工制作的,我使用分析器对其进行优化 - aos 处理大小非常好(交易有时会降至 1 字节)。

【讨论】:

Tom,我知道格式可以让我更加优化,例如将 datetime 转换为 yearxxxx 以来的刻度,short askPrice(spread) = double askPrice - double bidPrice。但是您愿意告诉我们您每秒读取多少个报价/交易吗? 好吧,我不处理双打 - 我将价格信息存储在包含刻度和编码的结构中。我还没有完全完成优化,但我们谈到每个线程每秒大约 200 万次(遗憾的是,由于每个仪器的增量信息和读者再次需要串行数据,因此很难并行化——但我可以将“阅读”与“处理”通过线程)。 一般性评论 - 我已经将此类数据序列化为自定义二进制序列化程序 - 编辑:它确实很快 - 并且不打扰 Protobuf。但是,我很想看看 pbuf 是如何存储 DateTimes 的。希望它很聪明并且存储 Int64 刻度而不是字符串表示! :0 同意,这是我还没有做的事情(读取和处理的线程),我用单线程方法每秒可以得到大约 600k 的报价。 在反向执行磁带(nxCore - 他们将数据存储在重放文件中的磁盘中)时,我从我的代理界面转去了大约 150 万,因此对于 mw 来说 600.000 是低的(他们做了很多事情,所以有更多的开销)。我建议使用分析器。还要确保正确缓冲 - BufferedStream - 以允许 IO 子系统在后台加载。

以上是关于为啥我的代码中的 protobuf-net 反序列化器比流式读取 csv 慢得多的主要内容,如果未能解决你的问题,请参考以下文章

使用 protobuf-net 反序列化字典

带有枚举的 Protobuf-net 反序列化异常

使用 protobuf-net 反序列化不同的列表

protobuf-net:不正确的线型反序列化 TimeSpan

使用 protobuf-net 反序列化 int& 类型

protobuf-net 反序列化错误 无效标签:0