为什么多个计算的运行速度快于数组访问?

我一直在编写一些用于进行粗略图像缩放的代码,但遇到了此性能问题。我最初的方法是创建从源图像到目标图像的像素索引的粗略映射,并将该映射存储在两个数组中,一个用于行,一个用于列,以便在预定大小之间重复缩放图像时快速访问。

这按预期工作,此时我决定创建另一种用于一次性缩放的方法,在该方法中,我将目标尺寸作为方法参数提供,而不是预先确定的目标大小,并即时计算映射。

我希望这种方法运行速度较慢-如果只使用一次,则可以节省计算初始映射的时间。但是,当我对这两种方法进行计时时,单次使用方法始终优于重复使用方法。

以下是相关的for循环:

重复使用,其中rowMap和columnMap是整数数组,用于存储与所需目标像素相对应的源像素的索引:

    for (int r = 0; r < rowMap.length; ++r) {
        for (int c = 0; c < columnMap.length; ++c) {
            target.setRGB(
                    c,
                    r,
                    source.getRGB(
                            columnMap[c],
                            rowMap[r]
                    )
            );
        }
    }

一次性使用,其中widthRatio和heightRatio由以下公式计算

private static double calculateRatio(int sourceValue, int targetValue) {
    return (double)sourceValue / (double)targetValue;
}

private static int mapByRatio(int targetValue, double sourceToTargetRatio) {
    return (int)Math.floor((double)targetValue * sourceToTargetRatio);
}

    for (int r = 0; r < targetHeight; ++r) {
        for (int c = 0; c < targetWidth; ++c) {
            target.setRGB(
                    c,
                    r,
                    source.getRGB(
                            mapByRatio(c, widthRatio),
                            mapByRatio(r, heightRatio)
                    )
            );
        }
    }

这是我的速度测试的示例输出-尽管确切的数字并不完全一致,但对于许多目标图像大小,方法运行时之间的比率是:

在13毫秒内设置地图。 具有预设地图的缩放图像在121毫秒内。 不带预设图的缩放图像在91毫秒内。 具有预设图的缩放图像在4443毫秒内反复出现。 没有预设映射的缩放图像会在3643毫秒内重复出现。

如果相关,在使用重复缩放方法之前,我会通过对此方法的调用来设置地图:

public static void setMaps(int sourceHeight, int sourceWidth, int targetHeight, int targetWidth) {
    columnMap = new int[targetWidth];
    rowMap = new int[targetHeight];
    double heightRatio = calculateRatio(sourceHeight, targetHeight);
    double widthRatio = calculateRatio(sourceWidth, targetWidth);
    for (int h = 0; h < targetHeight; ++h) rowMap[h] = mapByRatio(h, heightRatio);
    for (int w = 0; w < targetWidth; ++w) columnMap[w] = mapByRatio(w, widthRatio);
}

在我看来,这个结果似乎违反直觉-阵列访问几乎不需要花费任何时间,尽管对于现代CPU而言,单一使用方法中使用的计算并不是特别费力,但我仍然希望它们的运行速度比简单访问时慢预先计算的值。

如果我不得不猜测,我希望答案与Java或我的操作系统(Windows 10)如何分配和访问数组的内存有关。谁能对此提供进一步的见解?

评论