【问题标题】:common techniques to measure execution time provide different values (java)测量执行时间的常用技术提供不同的值(java)
【发布时间】:2016-05-14 18:56:51
【问题描述】:

我试图在不同类型的集合上测量不同操作的时间并想比较它们,但我得到的值在相同类型的集合上差别很大,比如因子 1000。我使用我常用的技术在这里阅读:How do I time a method's execution in Java?

我比较了 Hashset、TreeSet 和 LinkedHashSet。 我用 1 000 000 个整数填充集合,使用方法 contains() 并遍历集合。我测量了每次操作的时间,结果差异很大。所以我用相同类型的新集合做了第二次,我得到的执行时间似乎不合法。

同一类型的集合需要一次 1400 毫秒然后 300 毫秒才能被填充。这是为什么呢?

这是一个代码示例,它可能会让我的意思更清楚:

    public static void main(String[] args){

    HashSet<Integer> firstHashSet = new HashSet<>(predefinedSize);
    HashSet<Integer> secondHashSet = new HashSet<>(predefinedSize);
    LinkedHashSet<Integer> firstLinkedHashSet = new LinkedHashSet<>(predefinedSize);
    LinkedHashSet<Integer> secondLinkedHashSet = new LinkedHashSet<>(predefinedSize);
    TreeSet<Integer> firstTreeSet = new TreeSet<>();
    TreeSet<Integer> secondTreeSet = new TreeSet<>();
    int x = 9432;
    System.out.println("filling hashSet:        <" + fillSet(firstHashSet) + "> milliSeconds");
    System.out.println("filling linkedSet:      <" + fillSet(firstLinkedHashSet) + "> milliSeconds");
    System.out.println("filling treeSet:        <" + fillSet(firstTreeSet) + "> milliSeconds");
    System.out.println("-------------------------------------------------------------");
    System.out.println("filling hashSet:        <" + fillSet(secondHashSet) + "> milliSeconds");
    System.out.println("filling linkedSet:      <" + fillSet(secondLinkedHashSet) + "> milliSeconds");
    System.out.println("filling treeSet:        <" + fillSet(secondTreeSet) + "> milliSeconds");

这是我的一个填充集的样子:

private static int size = 1000000;
private static int predefinedSize = 2000000;

public static double fillSet(LinkedHashSet<Integer> myHashSet){
    double timeStart = System.nanoTime();
    for(int i=0; i<size; i++){
        myHashSet.add(i);
    }
    double time = (System.nanoTime() - timeStart)/ Math.pow(10, 6);
    return time;
}

输出如下:

filling hashSet:        <52.14022> milliSeconds
filling linkedSet:      <95.599435> milliSeconds
filling treeSet:        <2172.773956> milliSeconds
-------------------------------------------------------------
filling hashSet:        <59.096929> milliSeconds
filling linkedSet:      <1006.638126> milliSeconds
filling treeSet:        <241.36395> milliSeconds

你看到输出差异很大,我认为这取决于我的电脑的计算能力,但我没有在后台运行任何其他程序。 有人可以给我一个解释和/或解决方案吗?

【问题讨论】:

  • 也许垃圾收集器在填充数据时正在运行,所以时间不同。
  • 现在打开一些其他应用程序,如 chrome、explorer、photoshop 或任何游戏,然后检查基准,你就会知道哪里出了问题
  • 确保您打开繁重的任务,然后在打开相同应用的情况下对低处理器和高处理器进行相同的检查
  • 那么你就会得到答案
  • 有太多方法可以做出错误的基准测试。使用这个:openjdk.java.net/projects/code-tools/jmh

标签: java time set execution


【解决方案1】:

正如@kan 的评论所提到的,使用系统计时器并执行一百万次将提供截然不同的结果。您正在寻找的是一个微基准:

How do I write a correct micro-benchmark in Java?

至于您的时间安排到处都是的原因,您必须阅读有关计算机体系结构和 Java JVM 的信息。一些可能性:

  • 处理器中的动态时钟速度技术https://electronics.stackexchange.com/questions/62353/how-can-a-cpu-dynamically-change-its-clock-frequency - 您可以通过关闭 CPU 更改时钟速度的功能来消除这种可能性。
  • 您的集合有 100 万个 Int 类型的元素,即 4 MiB。考虑到非服务器 CPU 将具有 1 到 8 MiB 的缓存,该大小几乎是它是否适合您的处理器缓存的限制。如果在一次执行中,您的 100 万个元素在缓存中的停留时间比另一次执行时长,那么您将获得截然不同的执行时间。您可以通过使您的集合太小以至于绝对适合缓存(最大几十 KB)或太大以至于根本无法使用缓存(可能是 100 兆字节)来消除这种可能性。
  • 您可能没有运行任何其他应用程序,但仍有其他东西在您的计算机后台运行。 (防病毒、更新服务、10-20 项与操作系统内部工作相关的其他任务)
  • Java 虚拟机的行为可能有所不同(我不能确定这一点,因为我不是 JIT、GC 和其他可能影响执行时间的内部工作的专家)。微基准库将在很大程度上消除这种可能的差异。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-22
    • 1970-01-01
    • 2013-02-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多