当前位置: 首页 > 面试题库 >

读取/存储大量多维数据的最快方法?(Java)

韩宜春
2023-03-14
问题内容

关于三个嵌套循环,我有三个问题:

for (int x=0; x<400; x++)
{
    for (int y=0; y<300; y++)
    {
        for (int z=0; z<400; z++)
        {
             // compute and store value
        }
    }
}

而且我需要存储所有计算值。我的标准方法是使用3D阵列:

values[x][y][z] = 1; // test value

但是事实证明这很慢:完成此循环需要192毫秒,其中需要一个int分配

int value = 1; // test value

仅需66毫秒。

1)为什么数组这么慢?
2)为什么当我将其放入内部循环时它变得更慢:

values[z][y][x] = 1; // (notice x and z switched)

这需要4秒钟以上!

3)最重要的是:我可以使用一种数据结构,该结构与分配单个整数一样快,但是可以存储与3D数组一样多的数据?


问题答案:

1)为什么数组这么慢?

正如其他人指出的那样,您正在将苹果与橙子进行比较。三重数组很慢,因为它需要解引用三次(至少在内部-是的,“
Java中没有指针”)。但是再一次,您不能引用单个整数变量…

2)为什么当我将其放入内部循环时它变得更慢:

values[z][y][x] = 1; // (notice x and z switched)

因为您降低了缓存一致性。变化最快的索引应该是最后一个索引,以便大多数内存访问在同一缓存块内彼此相邻发生,而不是强迫处理器等待直到从主RAM中读取这些块。

3)最重要的是:我可以使用一种数据结构,该结构与分配单个整数一样快,但是可以存储与3D数组一样多的数据?

否。没有这样的结构,因为整数变量适合机器寄存器(甚至比处理器的内存高速缓存还快),并且始终可以比您要提及的任何其他事物更快地访问。处理器速度比主存储器速度快得多。如果您的“工作集”(您需要对其进行操作的数据)不适合寄存器或高速缓存,则您将不得不付出一定的代价才能从RAM(或更糟的是从磁盘)中获取数据。

话虽这么说,Java会对每个数组访问进行边界检查,而且似乎对优化边界检查并不聪明。以下比较可能是有趣的:

public static long test1(int[][][] array) {
    long start = System.currentTimeMillis();
    for ( int x = 0; x < 400; x++ ) {
        for ( int y = 0; y < 300; y++ ) {
            for ( int z = 0; z < 400; z++ ) {
                array[x][y][z] = x + y + z;
            }
        }
    }
    return System.currentTimeMillis() - start;
}

public static long test2(int [] array) {
    long start = System.currentTimeMillis();
    for ( int x = 0; x < 400; x++ ) {
        for ( int y = 0; y < 300; y++ ) {
            for ( int z = 0; z < 400; z++ ) {
                array[z + y*400 + x*400*300] = x + y + z;
            }
        }
    }
    return System.currentTimeMillis() - start;
}

public static void main(String[] args) {

    int[][][] a1 = new int[400][300][400];
    int[] a2 = new int[400*300*400];
    int n = 20;

    System.err.println("test1");
    for (int i=0; i<n; i++) {
        System.err.print(test1(a1) + "ms ");
    }
    System.err.println();
    System.err.println("test2");
    for (int i=0; i<n; i++) {
        System.err.print(test2(a2) + "ms ");
    }
    System.err.println();
}

在我的系统上,输出是

test1
164ms 177ms 148ms 149ms 148ms 147ms 150ms 151ms 152ms 154ms 151ms 150ms 148ms 148ms 150ms 148ms 150ms 148ms 148ms 149ms 
test2
141ms 153ms 130ms 130ms 130ms 133ms 130ms 130ms 130ms 132ms 129ms 131ms 130ms 131ms 131ms 130ms 131ms 130ms 130ms 130ms

因此,仍有一些改进的余地…但是我真的不认为这值得您花时间。



 类似资料:
  • 问题内容: 当给定一个MAX_BUFFER_SIZE的缓冲区以及一个远远超过该缓冲区的文件时,怎么办: 以MAX_BUFFER_SIZE的块读取文件? 尽快完成 我尝试使用NIO 和常规IO 事实证明, 常规IO在执行与NIO相同的操作时快约100倍 。我想念什么吗?这是预期的吗?有没有更快的方法来读取缓冲区块中的文件? 最终,我正在处理一个大文件,但我没有足够的内存来一次读取所有文件。相反,我想

  • 问题内容: 我在嵌入式Linux设备上使用Java 1.5,并且希望读取具有2MB int值的二进制文件。(现在是4字节的Big Endian,但我可以决定格式) 使用via 使用),这500 000个调用需要17秒才能读取,但是读入一个大字节缓冲区的文件需要5秒。 我如何更快地将该文件读入一个巨大的int []? 读取过程不应使用额外的512 kb。 下面使用的这段代码并不比java io中的r

  • 问题内容: 我在AI项目上使用Redis。 这个想法是让多个环境模拟器在许多cpu内核上运行策略。模拟器将体验(状态/操作/奖励元组列表)写入Redis服务器(重播缓冲区)。然后,培训过程将经验作为数据集读取以生成新策略。将新策略部署到模拟器,删除先前运行的数据,然后继续该过程。 大部分经验都记录在“状态”中。通常将其表示为尺寸为80 x 80的大型numpy数组。模拟器会以cpu允许的最快速度生

  • 问题内容: 我正在开发一个J2ME应用程序,该应用程序具有要存储在设备上的大量数据(大约1MB,但是可变)。我不能依靠文件系统,所以我卡住了记录管理系统(RMS),该系统允许多个记录存储,但每个记录存储空间都有限。我最初的目标平台Blackberry将每个限制为64KB。 我想知道是否还有其他人必须解决在RMS中存储大量数据的问题,以及他们如何进行管理?我正在考虑必须计算记录大小并在多个存储区中拆

  • 问题内容: 我必须在text [csv]文件中写入大量数据。我使用BufferedWriter写入数据,并且花费了大约40秒的时间来写入174 mb的数据。这是Java可以提供的最快速度吗? 注意:这40秒还包括从结果集中迭代和获取记录的时间。:) 174 mb用于结果集中的400000行。 问题答案: 你可以尝试删除BufferedWriter并直接使用FileWriter。在现代系统上,无论如

  • 问题内容: 我一直在寻找最快的方法来用有限的内存(大约64MB)在Java中再次读写大文件(0.5-1 GB),这是最快的方法。文件中的每一行代表一条记录,因此我需要逐行获取它们。该文件是普通文本文件。 我尝试了BufferedReader和BufferedWriter,但这似乎不是最好的选择。读写大小为0.5 GB的文件大约需要35秒钟,仅进行读写操作而不进行任何处理。我认为这里是写作的瓶颈,因