![](/img/trans.png)
[英]Fastest way to write a FloatBuffer or Float(float) array to a file in Java
[英]Write a float array to file in Java
我正在读取NetCDF文件,我想在每个数组中读取一个float数组,然后将float数组写入一个新文件。 如果我读取float数组然后迭代数组中的每个元素(使用DataOutputStream),我可以使它工作,但这非常非常慢,我的NetCDF文件超过1GB。
我尝试使用ObjectOutputStream,但这会写入额外的字节信息。
所以,回顾一下。 1.打开NetCDF文件2.从NetCDF文件中读取浮点数组x 3.在一步中将浮点数组x写入原始数据文件4.使用x + 1重复步骤2
好的,你有1 GB的读取和1 GB的写入。 根据您的硬盘驱动器,您可能会获得大约100 MB / s的读取速度和60 MB / s的写入速度。 这意味着读取和写入大约需要27秒。
您看到的驱动器速度是多少,速度比这慢多少?
如果你想在没有任何处理的情况下测试你的磁盘的速度,那么复制一个你最近没有访问过的文件需要多长时间(即它不在磁盘缓存中)这会让你知道你的最小延迟可以期望读取然后从文件中写入大部分数据(即不涉及处理或Java)
为了任何想知道如何做一个循环的数据副本的人的利益,即它不只是调用一个为你循环的方法。
FloatBuffer src = // readable memory mapped file.
FloatByffer dest = // writeable memory mapped file.
src.position(start);
src.limit(end);
dest.put(src);
如果您有混合类型的数据,您可以使用ByteBuffer,它一次性地复制一个字节,但实际上可以使用长或更宽的类型一次复制8个或更多字节。 即无论CPU能做什么。
对于小块,这将使用循环,但对于大块,它可以使用OS中的页面映射技巧。 在任何情况下,它是如何做的都没有在Java中定义,但它可能是复制数据的最快方法。
如果您将已经在内存中的文件复制到缓存文件,那么这些技巧中的大多数只会产生影响。 一旦从磁盘读取文件或文件太大而无法缓存物理磁盘的IO带宽,这是唯一真正重要的事情。
这是因为CPU可以将数据以6 GB / s的速度复制到主内存,但只能以60-100 MB / s的速度复制到硬盘驱动器。 如果CPU /内存中的副本比可能的速度慢2倍,10倍或50倍,它仍将等待磁盘。 注意:没有缓冲这是完全可能的,更糟糕的是,但如果你有任何简单的缓冲,CPU将比磁盘更快。
我遇到了同样的问题,并将我的解决方案转储到这里只是为了将来的反思。
迭代浮点数组并为每个浮点数调用DataOutputStream.writeFloat是非常缓慢的。 相反,将浮动自身转换为字节数组并一次写入该数组:
慢:
DataOutputStream out = ...;
for (int i=0; i<floatarray.length; ++i)
out.writeFloat(floatarray[i]);
快多了
DataOutputStream out = ...;
byte buf[] = new byte[4*floatarray.length];
for (int i=0; i<floatarray.length; ++i)
{
int val = Float.floatToRawIntBits(probs[i]);
buf[4 * i] = (byte) (val >> 24);
buf[4 * i + 1] = (byte) (val >> 16) ;
buf[4 * i + 2] = (byte) (val >> 8);
buf[4 * i + 3] = (byte) (val);
}
out.write(buf);
如果您的数组非常大(> 100k),请将其分解为块以避免堆溢出缓冲区数组。
1)写入时,使用BufferedOutputStream,你将获得100倍的加速。
2)阅读时,每次读取至少读取10K,可能100K更好。
3)发布你的代码。
如果您使用的是Unidata NetCDF库,那么您的问题可能不是写作,而是NetCDF库缓存机制。
NetcdfFile file = NetcdfFile.open(filename);
Variable variable = openFile.findVariable(variable name);
for (...) {
read data
variable.invalidateCache();
}
横向解决方案:
如果这是一次性生成(或者如果您愿意在Ant脚本中自动化它)并且您可以访问某种Unix环境,则可以使用NCDUMP而不是在Java中执行它。 就像是:
ncdump -v your_variable your_file.nc | [awk] > float_array.txt
如果需要,可以使用-p选项控制浮点数的精度。 我只是在一个3GB的NetCDF文件上运行它,它工作正常。 尽管我喜欢Java,但这可能是做你想做的最快捷的方式。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.