简体   繁体   English

测量执行时间的常用技术提供不同的值 (java)

[英]common techniques to measure execution time provide different values (java)

I was trying to measure the time of different operations on different type of sets and wanted to compare them, but the values I get differ very much, on the same type of set, like factor 1000. I use the common techniques I read here: How do I time a method's execution in Java?我试图在不同类型的集合上测量不同操作的时间并想比较它们,但我得到的值在相同类型的集合上有很大不同,比如因子 1000。我使用我在这里读到的常用技术: 如何在 Java 中为方法的执行计时?

I compared Hashset, TreeSet and LinkedHashSet.我比较了 Hashset、TreeSet 和 LinkedHashSet。 I filled the sets with 1 000 000 integers, used the methode contains() and iterated through the sets.我用 1 000 000 个整数填充集合,使用方法 contains() 并遍历集合。 I measured the time on each operations and the values differed very much.我测量了每个操作的时间,数值相差很大。 So I did this a second time with new sets of the same type and the execution times i get don't seem to be legit.所以我用相同类型的新集合第二次这样做了,我得到的执行时间似乎不合法。

The same type of set need once 1400 milliseconds then 300 milliseconds to be filled.相同类型的集合需要一次 1400 毫秒然后 300 毫秒才能被填充。 Why is that?这是为什么?

Here is a code sample, it may make it clearer what i mean:这是一个代码示例,它可能会使我的意思更清楚:

    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");

this is what one of my fillset looks like:这是我的一个圆角的样子:

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;
}

and the output is this:输出是这样的:

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

you see the output differs very much, I assume it depends on the computing power of my pc, but I dont run any other program on the background.你看到输出差异很大,我认为这取决于我电脑的计算能力,但我没有在后台运行任何其他程序。 Can someone give me an explanation and/or sollution to this?有人可以给我一个解释和/或解决方案吗?

As @kan's comment mentioned, using a system timer and executing something a million times will provide wildly varying results.正如@kan 的评论所提到的,使用系统计时器并执行一百万次将提供截然不同的结果。 What you're looking for is a microbenchmark:您正在寻找的是一个微基准:

How do I write a correct micro-benchmark in Java? 如何在 Java 中编写正确的微基准测试?

As for the reasons your timings are all over the place, you'll have to read up about computer architecture and the Java JVM.至于您的时间安排无处不在的原因,您必须阅读有关计算机体系结构和 Java JVM 的信息。 Some possibilities:一些可能性:

  • Dynamic clock speed technologies in processors https://electronics.stackexchange.com/questions/62353/how-can-a-cpu-dynamically-change-its-clock-frequency - You can eliminate this possibility by turning your CPU's ability to change its clock speed off.处理器中的动态时钟速度技术https://electronics.stackexchange.com/questions/62353/how-can-a-cpu-dynamically-change-its-clock-frequency - 您可以通过改变 CPU 的能力来消除这种可能性它的时钟速度关闭。
  • Your collection has 1 million elements of type Int which is 4 MiB.您的集合有 100 万个 Int 类型元素,即 4 MiB。 That size is just about at the limit of whether it will fit in your processor's cache or not, given that non-server CPUs will have between 1 and 8 MiB of cache.考虑到非服务器 CPU 将具有 1 到 8 MiB 的缓存,该大小几乎是它是否适合您的处理器缓存的极限。 If at one execution your 1 million elements stayed in the cache longer than in another execution, you'll get a wildly different execution time.如果在一次执行中您的 100 万个元素在缓存中停留的时间比在另一次执行中的时间长,您将获得截然不同的执行时间。 You can eliminate this possibility by making your collection either so small it definitely fits in cache (tens of kilobytes max), or so large that it won't work with cache at all (maybe a hundred megabytes).您可以通过使您的集合小到绝对适合缓存(最多数十 KB)或大到根本无法使用缓存(可能是 100 兆字节)来消除这种可能性。
  • You may not be running any other applications, but there's still other stuff running in the background on your computer.您可能没有运行任何其他应用程序,但仍有其他东西在您的计算机后台运行。 (Antivirus, update service, 10-20 other tasks related to your operating system's inner-workings) (防病毒、更新服务、与操作系统内部工作相关的 10-20 个其他任务)
  • The Java Virtual Machine's may behave differently (this I can't be too sure about because I'm no expert on the inner-workings of JIT, GC, and other stuff that may affect execution time). Java 虚拟机的行为可能有所不同(我对此不太确定,因为我不是 JIT、GC 和其他可能影响执行时间的东西的内部工作的专家)。 The microbenchmark libraries will largely remove this possible variance.微基准库将在很大程度上消除这种可能的差异。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM