我有很多longs long[]
数组,我需要对它们进行序列化并将它们保存到磁盘中供以后读取,注意每个数组都必须不时修改,但是在读取很频繁时写入很少。
通常我的应用程序只需要少量同时加载到内存中的应用程序。
在将阵列存储回磁盘之前,对每个阵列的编辑可以在内存中批量进行。
每个阵列都有数百到一百万个元素。
在我的应用程序中,将所需的数组加载到内存中非常重要。
在我的情况下,每个数组中的长值平均而言非常接近于另一个,即,从一个值到下一个值的差异 - 如果在单个数组中排序 - 小于整数。
采用类似trie的结构as presented here的解决方案似乎不适用于我的情况,因为在该解决方案中,数组值是已知的并且永远不会改变。
This solution here告诉我使用ByteBuffer
和LongBuffer
来加速I / O,但我的想法是以最紧凑的方式存储此类数组,以加快速度 - 通过减少我需要读取的大小来将它们加载到主存储器中所需的时间。
直觉是存储已排序的值并存储一个值与下一个值之间的差值,这个值在 - 平均值 - 在整数范围内,因此占用的空间更少。
但由于并非总是如此,我仍然无法将所有值存储为整数,因此这个方向看起来并不乐观。
我错过了一些明显的东西吗?
在I / O时间内实现这一目标的最有效方法是什么?
编辑一般而言,仅将性能视为I / O时间而不考虑磁盘空间,this question有更好的答案。
答案 0 :(得分:3)
您似乎非常重视紧凑性和速度。要使这些达到真正的最低水平,需要进行大量优化。而且很多,我的意思是比典型的开发人员要处理的更多。
不要自己动手,而是研究现有的数据库解决方案。这些数据库的开发人员花了数年时间来理解执行这些操作的最有效方法,并且开销远低于您的想象。更不用说免费获得的正确性和可靠性。
我会使用股票数据库解决方案(只需要输出一个mysql,maria或postgres实例并将其发送到城镇),看看它是否符合您的性能指标。如果没有,找到它不符合的具体指标并将其调整为那些。您要求的东西需要专业的数据知识和实验能力,这是互联网上没有人可以做到的(或者预期免费做的事情。)
答案 1 :(得分:2)
您仍然可以使用以下内容将数组元素编码为整数:
// The first int is the array length
buf.putInt(array.length);
long prev = 0;
for (long next : array) {
if (next - prev <= Integer.MAX_VALUE) {
// Delta is small. Change the sign and encode as int.
buf.putInt((int) (prev - next));
} else {
// Delta does not fit in 31 bits. Encode two parts of long.
buf.putInt((int) (next >>> 32));
buf.putInt((int) next);
}
prev = next;
}
请注意,31位增量将编码为负int
。在解码期间,最高(符号)位将告知值是否为delta或原始63位long
。在后一种情况下,您会阅读下一个int
并从两个整数中撰写一个63位long
:
// The first int is the array length
long[] array = new long[buf.getInt()];
long next = 0;
for (int i = 0; i < array.length; i++) {
int delta = buf.getInt();
if (delta <= 0) {
// Negative sign means the value is encoded as int delta.
next -= delta;
} else {
// Positive sign means the value is encoded as raw long.
// Read the second (lower) part of long and combine it with the higher part.
next = (long) delta << 32 | (buf.getInt() & 0xffffffffL);
}
array[i] = next;
}
如果数组中的所有值都是正数,则此方法有效。如果有正值和负值,请将它们分成两个数组。
顺便说一句,如果邻居值接近,像GZIP(或像LZ4这样的更快的替代品)的流压缩也会很好地工作。请参阅GZIPOutputStream。