我有一个解决方案,其中我需要非常快速地将对象读取到内存中,但是二进制流可能被压缩缓存在内存中,以节省磁盘io上的时间。
我已经修补了不同的解决方案,显然XmlTextWriter和XmlTextReader不是很好,内置的二进制序列化也不是。Protobuf-net很好,但还是有点慢。以下是一些统计数据:
文件大小XML: 217kb
文件大小二进制:87kb
压缩二进制:26KB
压缩XML: 26KB
使用XML反序列化(XmlTextReader):8.4SEK
使用二进制进行反序列化(Protobuf-net):6.2 sek
使用二进制wo string.interning反序列化(Protobuf-net):5.2SEK
使用内存中的二进制文件进行反序列化: 5.9 Sek
将二进制文件解压缩到内存的时间: 1.8瑞典克朗
使用可扩展标记语言序列化(XmlTextWriter):11SEK
使用二进制序列化(Protobuf):4 sek
使用二进制长度前缀序列化(Protobuf-net):3.8 sek
这让我思考,似乎(如果我错了,请纠正我)反序列化的主要罪魁祸首是实际的字节转换,而不是IO。如果是这样的话,它应该是使用新的并行扩展的候选者。
因为我是一个二进制IO的新手,所以在我花时间解决这个问题之前,我会很感谢你的一些建议:)
为了简单起见,假设我们想反序列化一个没有可选字段的对象列表。我的第一个想法是简单地用一个长度前缀来存储每个。将每个对象的byte[]读取到byte[]列表中,并使用PLINQ执行byte[] ->对象反序列化。
然而,使用这种方法,我仍然需要单线程读取byte[],所以也许可以将整个二进制流读取到内存中(对于这种btw来说,多大的二进制文件是可行的?)在二进制文件的开头存储有多少个对象,以及它们的长度和偏移量。然后,我应该能够只创建ArraySegments或其他东西,并以并行方式进行分块。
你们怎么看,这是可行的吗?
发布于 2009-12-23 18:48:10
我经常做这样的事情,没有什么比使用BinaryReader读取内容更好的了。据我所知,没有比使用BinaryReader.ReadInt32读取32位整数更快的方法了。
您可能还会发现,将其并行化并重新连接起来的开销太大了。如果你真的想走并行路线,我建议使用多线程来读入多个文件,而不是使用多线程来读取多个块中的一个文件。
您还可以调整块大小,使其与磁盘块大小相匹配,但应用程序和磁盘之间存在太多抽象级别,这可能会浪费时间。
发布于 2009-12-22 21:29:34
二进制文件可以由多个线程同时读取。为此,必须使用适当的访问/共享修饰符打开它。然后每个线程都可以在该文件中获得自己的偏移量和长度。因此,并行读取不是问题。
让我们假设您将坚持使用简单的二进制格式:每个对象都以其长度作为前缀。知道您可以“滚动”文件,并知道放置反序列化线程的偏移量。
反序列化算法可以看起来像这样: 1)分析文件(将其分成几个相对较大的块,块边界应与对象边界一致) 2)产生必要数量的反序列化线程,并用适当的偏移和长度“指示”它们读取3)将所有反序列化线程的结果组合到一个列表中
发布于 2009-12-23 17:52:58
让我开始思考,似乎(如果我错了,请纠正我)反序列化的罪魁祸首是实际的字节转换,而不是IO。
不要假设时间都花在哪里了,给自己找个分析器,找出答案。
https://stackoverflow.com/questions/1935109
复制相似问题