我需要将大量小对象的数据(大约 2gigs)序列化到一个文件中,以便稍后由另一个 Java 进程处理。性能有点重要。任何人都可以提出一个好的方法来实现这一目标吗?
9 回答
你看过谷歌的协议缓冲区吗?听起来像是一个用例。
我不知道为什么 Java 序列化被否决,这是一个完全可行的机制。
从原帖看不清楚,但是堆里的所有2G数据是同时的吗?还是你在倾倒其他东西?
开箱即用,序列化不是“完美”的解决方案,但如果您在对象上实现 Externalizable,序列化可以正常工作。序列化的大笔开销是弄清楚要写什么以及如何写。通过实施 Externalizable,您可以摆脱这些决策,从而大大提高性能并节省空间。
虽然 I/O 是写入大量数据的主要成本,但转换数据的附带成本也可能非常昂贵。例如,您不想将所有数字都转换为文本然后再转换回来,最好尽可能以更原生的格式存储它们。ObjectStream 具有在 Java 中读取/写入本机类型的方法。
如果您的所有数据都设计为加载到单个结构中,那么您可以在实现 Externalizable 之后简单地执行 ObjectOutputStream.writeObject(yourBigDatastructure)。
但是,您也可以遍历您的结构并在各个对象上调用 writeObject。
无论哪种方式,您都将需要一些“objectToFile”例程,也许是几个。这就是 Externalizable 所提供的有效的方式,以及一个框架来遍历你的结构。
当然,另一个问题是版本控制等。但是由于您自己实现了所有序列化例程,因此您也可以完全控制它。
你试过java序列化吗?您可以使用ObjectOutputStream将它们写出来,然后使用ObjectInputStream将它们读回。当然,课程必须是Serializable
. 这将是一种省力的解决方案,并且由于对象以二进制形式存储,因此它既紧凑又快速。
我立即想到的一种最简单的方法是使用 NIO 的内存映射缓冲区(java.nio.MappedByteBuffer)。使用与一个对象的大小相对应的单个缓冲区(大约),并在必要时将它们刷新/附加到输出文件。内存映射缓冲区非常有效。
协议缓冲区:有意义。这是他们维基的摘录:http ://code.google.com/apis/protocolbuffers/docs/javatutorial.html
获得更快的速度
默认情况下,protocol buffer 编译器尝试通过使用反射来生成更小的文件来实现大多数功能(例如解析和序列化)。但是,编译器也可以为您的消息类型生成显式优化的代码,通常提供一个数量级的性能提升,但也会使代码大小加倍。如果分析显示您的应用程序在协议缓冲区库中花费了大量时间,您应该尝试更改优化模式。只需将以下行添加到您的 .proto 文件中:
选项 optimize_for = 速度;
重新运行协议编译器,它将生成极快的解析、序列化和其他代码。
我开发了 JOAFIP 作为数据库替代品。
Apache Avro也可能有用。它被设计为独立于语言并具有流行语言的绑定。
看看这个。
您可能应该考虑一个数据库解决方案——所有数据库所做的都是优化它们的信息,如果您使用 Hibernate,您将保持对象模型不变,甚至不需要考虑您的数据库(我相信这就是为什么它被称为 hibernate,只是存储您的数据,然后将其恢复)
如果性能非常重要,那么您需要自己编写。您应该使用紧凑的二进制格式。因为对于 2 GB,磁盘 I/O 操作非常重要。如果您使用任何人类可读的格式,例如 XML 或其他脚本,您可以将数据的大小调整为 2 倍或更多。
根据数据,如果您以低压缩率动态压缩数据,则可以加快速度。
Java 序列化完全不行,因为在读取 Java 时会检查每个对象是否是对现有对象的引用。