磁盘上的Java阵列大容量刷新
我有两个数组(int和long),其中包含数百万个条目。到目前为止,我一直在使用DataOutputStream并使用长缓冲区来实现这一点,因此磁盘I/O成本变得很低(nio也或多或少与我有巨大的缓冲区相同,所以I/O访问成本很低),具体来说,使用磁盘上的Java阵列大容量刷新,java,arrays,Java,Arrays,我有两个数组(int和long),其中包含数百万个条目。到目前为止,我一直在使用DataOutputStream并使用长缓冲区来实现这一点,因此磁盘I/O成本变得很低(nio也或多或少与我有巨大的缓冲区相同,所以I/O访问成本很低),具体来说,使用 DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("abc.txt"),1024*1024*100)); for(in
DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("abc.txt"),1024*1024*100));
for(int i = 0 ; i < 220000000 ; i++){
long l = longarray[i];
dos.writeLong(l);
}
DataOutputStream dos=newdataoutputstream(newbufferedoutputstream(newfileoutputstream(“abc.txt”),1024*1024*100));
对于(int i=0;i<220000000;i++){
长l=长数组[i];
dos.writeLong(l);
}
但这需要几秒钟(超过5分钟)的时间。实际上,我想要的是大容量刷新(某种主内存到磁盘内存映射)。为此,我在和中找到了一个很好的方法。但是,我不明白如何在我的javac中使用它。有人能帮我做这件事吗,或者用其他方法做得更好吗
我正在使用16GB内存和2.13 GhZ[CPU]运行it服务器
我怀疑这个问题与您的Java代码有关
您的文件系统似乎非常慢(至少比本地磁盘慢十倍)
我会做两件事:
在我的机器上,带有SSD的3.8 GHz i7
DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("abc.txt"), 32 * 1024));
long start = System.nanoTime();
final int count = 220000000;
for (int i = 0; i < count; i++) {
long l = i;
dos.writeLong(l);
}
dos.close();
long time = System.nanoTime() - start;
System.out.printf("Took %.3f seconds to write %,d longs%n",
time / 1e9, count);
使用内存映射文件
final int count = 220000000;
final FileChannel channel = new RandomAccessFile("abc.txt", "rw").getChannel();
MappedByteBuffer mbb = channel.map(FileChannel.MapMode.READ_WRITE, 0, count * 8);
mbb.order(ByteOrder.nativeOrder());
long start = System.nanoTime();
for (int i = 0; i < count; i++) {
long l = i;
mbb.putLong(l);
}
channel.close();
long time = System.nanoTime() - start;
System.out.printf("Took %.3f seconds to write %,d longs%n",
time / 1e9, count);
// Only works on Sun/HotSpot/OpenJDK to deallocate buffer.
((DirectBuffer) mbb).cleaner().clean();
final FileChannel channel2 = new RandomAccessFile("abc.txt", "r").getChannel();
MappedByteBuffer mbb2 = channel2.map(FileChannel.MapMode.READ_ONLY, 0, channel2.size());
mbb2.order(ByteOrder.nativeOrder());
assert mbb2.remaining() == count * 8;
long start2 = System.nanoTime();
for (int i = 0; i < count; i++) {
long l = mbb2.getLong();
if (i != l)
throw new AssertionError("Expected "+i+" but got "+l);
}
channel.close();
long time2 = System.nanoTime() - start2;
System.out.printf("Took %.3f seconds to read %,d longs%n",
time2 / 1e9, count);
// Only works on Sun/HotSpot/OpenJDK to deallocate buffer.
((DirectBuffer) mbb2).cleaner().clean();
在较慢的机器上打印
Took 1.180 seconds to write 220,000,000 longs
Took 0.990 seconds to read 220,000,000 longs
这里有没有其他方法可以避免这种情况?因为我的主内存中已经有了这个阵列,我不能分配超过500 MB的内存来完成这个任务 这不会使用小于1KB的堆。如果你看看这个电话前后使用了多少内存,你通常不会看到任何增加 另一件事,这是不是给有效的加载也意味着MappedByteBuffer 根据我的经验,使用内存映射文件是迄今为止最快的,因为这样可以减少系统调用和复制到内存中的次数 因为,在一些文章中,我发现read(buffer)可以提供更好的加载性能。(我检查了一下,真的快了2.2亿整数数组-浮点数组读取5秒) 我想读那篇文章,因为我从来没有看过
另一个问题:readLong在读取代码输出文件时出错 性能验证的一部分是以本机字节顺序存储值。writeLong/readLong总是使用大端字节格式,这在本机采用小端字节格式的Intel/AMD系统上要慢得多
您可以将字节顺序设置为big-endian,这会降低它的速度,也可以使用本机排序(DataInput/OutputStream仅支持big-endian)这确实不应该超过几秒钟。我会尝试将缓冲区大小减少到32KB。缓冲区大于此值实际上可能会更慢。根据硬件的不同,您应该能够以至少40到400 MB/s的速度写入数据。@PeterLawrey,我修改了代码。有什么问题吗?但是,这需要498秒。您是在向本地文件系统(而不是网络文件系统)写入文件吗?您所说的“然而,无法理解如何在我的javac中使用它”是什么意思只需下载归档文件,获取Java文件Ti/jni/BulkDataOutputStream.Java并将其添加到您正在编译的类中。@aix,我正在使用16GB内存和2.13GHz内存运行it服务器,Java代码将其写入本地内存。谢谢,我会检查。系统中似乎有些地方存在缺陷。我得问问。谢谢,再次非常感谢。问题是,我必须用这个命令分配另一个相同大小的数组(2.64 GB,我有另一个int数组,相同大小):map(FileChannel.MapMode.READ_WRITE,0,count*8)。这里有没有其他方法可以避免这种情况?因为我的主内存中已经有了这个阵列,我不能分配超过500 MB的内存来完成这个任务?另一件事,这是不是给有效的加载也意味着MappedByteBuffer?因为,在一些文章中,我发现read(buffer)可以提供更好的加载性能。(我检查了其中一个,真的快了2.2亿整数数组-浮点数组读取5秒)。另一个问题:readLong在读取代码输出文件时出错。我作为编辑回复了您的评论。顺便说一句:如果您只使用MappedByteBuffer而不是int[]或long[]或double[],那么它不会使用太多堆(并且您不必做任何事情来将数据写入磁盘),谢谢。我发现read(buf)从中提供了很好的性能。另一件事,你能展示一下,如何使用MappedByteBuffer以一种有效的方式阅读吗?增加了一个如何阅读顺序的例子。注意:您还可以随机访问数据,以便您可以在任何地方开始/结束。
Took 0.568 seconds to write 220,000,000 longs
Took 1.180 seconds to write 220,000,000 longs
Took 0.990 seconds to read 220,000,000 longs