【问题标题】:Why does my algorithm become faster after having executed several times? (Java)为什么我的算法在执行了几次后变得更快了? (爪哇)
【发布时间】:2023-04-05 17:55:01
【问题描述】:

我有一个数独求解算法,我的目标是尽可能快地完成它。为了测试这个算法,我多次运行它并计算平均值。在注意到一些奇怪的数字后,我决定一直打印并得到以下结果:

Execution Time : 4.257746 ms (#1)
Execution Time : 7.610686 ms (#2)
Execution Time : 6.277609 ms (#3)
Execution Time : 7.595707 ms (#4)
Execution Time : 7.610131 ms (#5)
Execution Time : 5.011104 ms (#6)
Execution Time : 3.970937 ms (#7)
Execution Time : 3.923783 ms (#8)
Execution Time : 4.070238 ms (#9)
Execution Time : 4.765347 ms (#10)
Execution Time : 0.818264 ms (#11)
Execution Time : 0.620216 ms (#12)
Execution Time : 0.679021 ms (#13)
Execution Time : 0.643516 ms (#14)
Execution Time : 0.718408 ms (#15)
Execution Time : 0.744481 ms (#16)
Execution Time : 0.760569 ms (#17)
Execution Time : 0.80384 ms (#18)
Execution Time : 0.75946 ms (#19)
Execution Time : 0.802176 ms (#20)
Execution Time : 66.032508 ms : average = 3.3016254000000003

在 10 到 15 次执行后(随机变化),算法的性能显着提高。如果我运行它几百次,它最终会稳定在 0.3ms 左右。请注意,我在此循环之前运行了一次算法,以便 JIT 执行此操作。

此外,如果我在运行循环之前让线程休眠 2 秒,我的所有时间都是 1 毫秒 (+/- 0.2)。

此外,如果我在循环之前解决了大约 500 次通用数独(对角线为 1-9 的网格),我的所有时间都在 0.3 毫秒左右(+/- 0.02)。

每个解决方案都是相同的。所有值都被重置。

所以我的问题是多方面的:

-为什么在连续求解后每次求解时间都会缩短?

-为什么在 10-15 次解决后我的解决时间突然下降?

【问题讨论】:

  • JIT 不必在第一次运行时进行优化。事实上,它很可能不会,因为优化代码的成本是不合理的,除非它被证明是一段重要的代码(运行足够频繁)。
  • 你无意中创造了一个可以解决数独的人工生命体,它可能会进化成天网。立即退出并开始销售椰子。
  • 使用-XX:+PrintCompilation java 选项检查 JIT 编译。
  • 有 JVM 启动选项可以实时显示关于(去)优化的 JIT 决策:blog.headius.com/2009/01/my-favorite-hotspot-jvm-flags.html
  • 在这个范围内,可能是因为其他程序使用了多少cpu

标签: java performance algorithm jvm jit


【解决方案1】:

很可能 - JVM 在多次运行后优化了它的执行。

除此之外,应用程序本身还可以做一些改进执行结果的事情。

如果不详细了解您运行的是什么,就很难说得更准确。

您是否使用外部资源 - 数据库连接、JMS 队列/主题等? 你使用缓存吗?

所有重要的...

【讨论】:

  • 我又添加了一些 cmets。
  • 我只用纯简单的java。没有队列,没有缓存,没有线程,没有数据库。应用程序在每次循环执行之间完全重置其数据。
  • 这就是我所说的——如果不确切知道你做了什么很难说。如果您不使用外部资源和缓存 - 那么是 JIT 改善了执行结果。
【解决方案2】:

这是因为JITJVM 对该方法进行一定次数的频繁调用后编译该方法。在实践中,方法在第一次被调用时不会被编译。对于每个方法,JVM 维护一个调用计数,每次调用该方法时都会递增。 JVM 解释一个方法,直到它的调用计数超过JIT compilation threshold。当调用计数达到阈值时,JIT 编译并优化bytecodes 以便在下次被JVM 调用时运行得更快。因此,在您的情况下,每执行 10 到 15 次(随机),算法的性能就会显着提高。

【讨论】:

  • 应用程序本身可能有一些东西导致了改进。例如缓存。在第一次运行时,可能已经从外部存储中轮询了一些数据,但在随后的调用中,可能已经从缓存中获取了相同的数据。
  • 是的,JIT 自己做 - 相对较低的级别。但我说的是纯业务缓存。例如 - 您的应用程序加载公司(它们很少更改),因此使用缓存可能会显着提高处理时间。没有 JIT 可以为您完成。
  • @AlexKreutznaer 我对此表示怀疑,因为 OP 可能是他/她自己编写的代码。而且它是一个数独求解器,我认为缓存没有多大用处。
  • @AlexKreutznaer:是的,你是对的。一般来说,应用程序本身的这种缓存会提高应用程序的性能。因为在这种情况下,JVM 每次需要它时都不会创建该对象。应用程序..尽管现代 JVM 创建对象所消耗的资源和时间现在几乎可以忽略不计,但对于大型对象来说仍然很重要。
  • @VishalK 我开发了许多业务应用程序。问题不在于对象创建,问题通常在于您花费时间获取外部资源并从中获取数据。这就是适当的缓存有很大帮助的地方。
猜你喜欢
  • 2020-04-02
  • 1970-01-01
  • 2015-04-23
  • 1970-01-01
  • 2018-09-30
  • 1970-01-01
  • 1970-01-01
  • 2021-06-16
  • 1970-01-01
相关资源
最近更新 更多