【问题标题】:Integer addition performance in JavaJava中的整数加法性能
【发布时间】:2012-01-31 17:05:18
【问题描述】:

我正在测试 Java 中整数加法的性能。我这样做的方法是对数十亿个整数求和。我用于测试的示例文件是一个 1G 的二进制文件。我的程序很简单,如下面的sn-p所示。

int result = 0;
FileChannel fileChannel = new FileInputStream(filename).getChannel();
long fileSize = fileChannel.size();
intBuffer = fileChannel.map(MapMode.READ_ONLY, startPosition, fileSize).asIntBuffer();

try {
  while (true) {
    result += intBuffer.get();
  }
} catch (BufferUnderflowException e) {
  System.out.println("Complete reading");
}

从上面可以看出,它只是在每个循环中执行两个操作

  • 从文件中读取整数
  • 整数加法

这个程序在我的机器上运行了大约 2 分钟。我还进行了另一次不添加的测试,将result += intBuffer.get() 更改为result = intBuffer.get()(如下面的sn-p 所示)。

int result = 0;
FileChannel fileChannel = new FileInputStream(filename).getChannel();
long fileSize = fileChannel.size();
intBuffer = fileChannel.map(MapMode.READ_ONLY, startPosition, fileSize).asIntBuffer();

try {
  while (true) {
    result = intBuffer.get();
  }
} catch (BufferUnderflowException e) {
  System.out.println("Complete reading");
}

在这种情况下,整个程序在 1 秒内完成。与上面的同级变体相比,与 IO 读取相比,整数加法似乎在 CPU 时间中占主导地位。

为了证明我的猜测,我编写了另一个基准程序,它执行的加法次数与上面的示例相同。

int result = random.nextInt();
int other = random.nextInt();
int num = 1073741824 / 4;
while(num-- > 0) {
  result += other;
}

在相同数量的整数加法加上整数增量操作的情况下,这个程序不到 1 秒就完成了。

我的问题是

  • 是什么导致了这些运行之间的主要时间差异? Java 编译器是否会优化最后一个?

感谢任何想法。

【问题讨论】:

  • 您可能想澄清“第二个”的含义。我认为它是指您在result = intBuffer.get() 进行的测试,但2 个答案(到目前为止)似乎假设您的意思是您使用random.nextInt() 的那个。
  • 发生这种情况是因为操作系统将最近使用的文件保存在内存中。尝试以相反的顺序再运行一次测试。
  • @Baqueta,我调整了措辞以使问题更清楚。

标签: java performance integer addition


【解决方案1】:

那是因为磁盘 I/O 与 CPU 相比非常慢。

在第一种情况下,您正在读取文件。所以你受到磁盘访问的约束。

在第二种情况下,一切都在 CPU 中。


所以这与加法的速度无关。

  • 第一种情况受磁盘速度的限制。
  • 第二种情况(可能)受到随机数生成器速度的限制。

至于result = intBuffer.get()为什么好像很快:(从cmets拉出来的)

我能想到的两个可能的原因:

  • JIT 的 Dead Code Elimination 正在优化除最后一次迭代之外的所有内容。
  • I/O 缓冲:操作系统在第一次读取后将整个文件缓冲到内存中。*

*所以后续的传球速度会非常快。通过重新排序测试或每次清除 I/O 缓存来轻松测试这种情况

【讨论】:

  • 他说他的第二次测试运行没有添加,只是从同一个文件中读取并在 1 秒内完成。
  • 第一种情况,我也测试了没有任何整数加法,将循环中的语句从result += intBuffer.get()替换为result = intBuffer.get(),并在1秒内完成。
  • 可能是由于Dead Code Elimination。不过我不确定...也许 JIT 足够聪明,可以意识到唯一的最后一次迭代很重要...
  • @Mysticial 是的,这是有道理的。
  • 另外,它也可能是由于缓冲。在第一次传递数据后,操作系统将整个文件缓冲在内存中。所以后续的传球速度会非常快。通过重新排序测试或每次清除 I/O 缓存来轻松测试这种情况。
【解决方案2】:

最大的不同是你在做文件 IO。对整数求和不是问题。但它正在阅读它们。我不是很确定,但我认为在两分钟内读取 1 GB 的数据是可以接受的。

【讨论】:

    【解决方案3】:

    这是因为 I/O 访问是您的瓶颈。仅在添加阶段计算时间。您始终可以将所有数据加载到 RAM(例如 int 数组)并从此时开始计算时间。

    无论您执行什么基准测试,请记住数据准备阶段不应计入算法的执行时间。

    【讨论】:

      猜你喜欢
      • 2011-01-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-23
      • 2013-04-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多