我有一个解决方案,我需要非常快速地将对象读入内存,但是二进制流可能会缓存压缩在内存中以节省磁盘 io 时间。
我尝试过不同的解决方案,显然 XmlTextWriter 和 XmlTextReader 不太好,内置的二进制序列化也不是很好。 Protobuf-net 非常好,但还是有点太慢了。以下是一些统计数据:
文件大小 XML:217 kb
二进制文件大小:87 kb
压缩二进制文件:26 KB
压缩的 XML:26 KB
使用 XML (XmlTextReader) 反序列化:8.4 sek
使用二进制反序列化 (Protobuf-net):6.2 秒
使用二进制反序列化 wo string.interning (Protobuf-net):5.2 sek
从内存中用二进制反序列化:5.9 Sek
将二进制文件解压到内存中的时间:1.8 sek
使用 Xml 序列化 (XmlTextWriter):11 秒
使用二进制序列化 (Protobuf):4 秒
使用二进制长度前缀序列化(Protobuf-net):3.8 sek
这让我想到,似乎(如果我错了请纠正我)反序列化的主要罪魁祸首是实际的字节转换而不是 IO。如果是这样的话,那么它应该是使用新的并行扩展的候选者。
由于我在二进制 IO 方面有点新手,所以在我花时间解决问题之前,我会很感激一些输入:)
为简单起见,假设我们要反序列化一个没有可选字段的对象列表。我的第一个想法是简单地用长度前缀存储每个。将每个的 byte[] 读取到 byte[] 列表中,并使用 PLINQ 执行 byte[] -> 对象反序列化。
然而,使用该方法我仍然需要单线程读取 byte[],因此也许可以将整个二进制流读入内存(顺便说一句,多大的二进制文件是可行的?)并在二进制文件的开头而是存储有多少个对象以及它们的每个长度和偏移量。然后我应该能够只创建 ArraySegments 或其他东西并并行地进行分块。
那么大家怎么看,可行吗?
最佳答案
我经常做这样的事情,没有什么比使用 BinaryReader 读入内容更好的了。据我所知,没有比使用 BinaryReader.ReadInt32 读入 32 位整数更快的方法了。
您可能还会发现使它并行并重新连接在一起的开销太大。如果你真的想走并行路线,我建议使用多个线程读取多个文件,而不是多个线程以多个 block 读取一个文件。
您也可以调整 block 大小以使其与磁盘 block 大小相匹配,但是您的应用程序和磁盘之间存在太多抽象级别,这可能会浪费时间。
关于c# - 并行二进制反序列化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1935109/