4

我正在读取 NetCDF 文件,我想将每个数组作为浮点数组读取,然后将浮点数组写入新文件。如果我读入浮点数组然后遍历数组中的每个元素(使用 DataOutputStream),我可以让它工作,但这非常非常慢,我的 NetCDF 文件超过 1GB。

我尝试使用 ObjectOutputStream,但这会写入额外的信息字节。

所以,回顾一下。1. 打开 NetCDF 文件 2. 从 NetCDF 文件中读取浮点数组 x 3. 一次性将浮点数组 x 写入原始数据文件 4. 使用 x+1 重复步骤 2

4

5 回答 5

3

好的,您有 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,它名义上一次复制一个字节,但实际上可以使用 long 或更宽的类型一次复制 8 个或更多字节。即无论CPU 能做什么。

对于小块,这将使用循环,但对于大块,它可以使用操作系统中的页面映射技巧。无论如何,它是如何做的并没有在 Java 中定义,但它可能是复制数据的最快方式。

如果您将已经在内存中的文件复制到缓存文件中,大多数这些技巧只会产生影响。一旦您从磁盘读取文件或文件太大而无法缓存物理磁盘的 IO 带宽,这是唯一真正重要的事情。

这是因为 CPU 可以以 6 GB/s 的速度将数据复制到主内存,但只能以 60-100 MB/s 的速度复制到硬​​盘。如果 CPU/内存中的副本比它可能的速度慢 2 倍、10 倍或 50 倍,它仍然会等待磁盘。注意:如果没有缓冲,这是完全可能的,而且更糟,但如果你有任何简单的缓冲,CPU 将比磁盘快。

于 2011-09-13T17:30:44.967 回答
1

1) 写入时,使用 BufferedOutputStream,您将获得 100 倍的加速。

2)读的时候,每次读至少10K,大概100K比较好。

3)发布您的代码。

于 2011-12-01T23:47:35.587 回答
1

我遇到了同样的问题,并将我的解决方案放在这里以供将来参考。

遍历浮点数组并为每个浮点数调用 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),请将其分成块以避免缓冲区数组的堆溢出。

于 2012-10-29T08:45:00.477 回答
0

如果您使用的是Unidata NetCDF 库,您的问题可能不是写作,而是 NetCDF 库缓存机制。

     NetcdfFile file = NetcdfFile.open(filename);
     Variable variable = openFile.findVariable(variable name);
     for (...) {
          read data
          variable.invalidateCache();
      }
于 2011-10-21T17:51:45.737 回答
0

横向解决方案:

如果这是一次性的生成(或者如果您愿意在 Ant 脚本中自动化它)并且您可以访问某种 Unix 环境,那么您可以使用NCDUMP而不是在 Java 中执行它。就像是:

ncdump -v your_variable your_file.nc | [awk] > float_array.txt

如果需要,可以使用 -p 选项控制浮点数的精度。我只是在一个 3GB 的 NetCDF 文件上运行它,它运行良好。尽管我很喜欢 Java,但这可能是做你想做的最快的方法。

于 2011-10-23T02:43:58.477 回答