3

简而言之,我的程序:

我有一个程序,可以针对一个整数数组连续运行几种排序算法,并分别计时。GUI 允许用户选择数组大小和用于填充要排序的数组的各种随机数范围。每次单击“排序”按钮都会获取用户的数组值,构造一个新数组,然后为每个排序算法创建一个数组的克隆,使用.clone().

问题:

当第二次单击“排序”按钮时,排序会自行改进。

某处发生了我不明白的优化。

这是一个问题的原因:如果用户没有更改他们的数组设置并再次运行排序方法,那么确实使用新的随机数构造了一个新数组,但随机数范围保持不变,因此运行时间,在 125k 的列表中,应该保持大致相同....不会提高 300%。

所以这是我所面临的演示程序。它仅使用一种排序,即 Java 的本机排序来演示该问题。它还使用硬编码值来构造要排序的随机 int 数组 - 但每次“输入”按下时都会这样做。我认为这个模拟准确地反映了我的程序,因为这里也发生了同样的“错误”。

为什么第二次排序更快?

...每次运行都会使用新值重建数组,那么它如何变得更快?

package sortTooFast;

import java.util.Arrays;
import java.util.Scanner;

public class SortTooFast {
    public static final int ARRAY_SIZE = 500000;
    public static final int MIN_RANGE = 0;
    public static final int MAX_RANGE = 100;
    public static final int INCLUSIVE = 1;
    
    int[] sortingArray;

    public static void main(String[] args) {
        SortTooFast test = new SortTooFast();
        test.run();
    }
    
    // Run program.
    public void run(){
        while(true){    
            
            // Assign int[] filled with random numbers.
            sortingArray = getArray();                  

            // Inform user.
            System.out.println("\nPress return key to run sort!");
            
            // Wait for user.
            new Scanner(System.in).nextLine();
            
            System.out.println("First 15 elements to be sorted:");
            
            // Print a small section of the array; prove not sorted
            for (int i = 0; i < 15; i++){
                System.out.printf("%4d", sortingArray[i]);
            }
            
            // Perform sort.
            runNativeSort(sortingArray);
        }
    }

    // Run native java sort.
    private void runNativeSort(int[] array) {
        // Start timer
        long startTime = System.currentTimeMillis();
        
        // Perform sort.
        Arrays.sort(array);
        
        // End timer
        long finishTime = System.currentTimeMillis();
        
        // Running time.
        long runTime = finishTime - startTime;
        
        // Report run time.
        System.out.println("\nRun time: " +runTime);        
    }

    // Obtain an array filled with random int values.
    private int[] getArray() {
        // Make int array.
        int[] mArray = new int[ARRAY_SIZE];
        
        // Length of array.
        int length = mArray.length;
        
        // Fill array with random numbers.
        for(int counter = 0; counter < length; counter++){
            int random = MIN_RANGE + (int)(Math.random() * ((MAX_RANGE - MIN_RANGE) + INCLUSIVE));
            mArray[counter] = random;
        }
        return mArray;
    }
}
4

1 回答 1

9

为什么第二次排序更快?

因为到那时,JIT 已经将字节码优化为更快的本机代码。

在对此类事物进行基准测试时,您需要应对两种影响:

  1. 首先 JIT 代码所花费的时间
  2. 本机代码随着时间的推移而改进的方式,因为 JIT 越来越难以优化它。

通常,您可以通过在开始计时之前运行代码足够长的时间以使其完全优化来减少这种影响以实现稳定状态。

此外,您应该在基准测试时使用System.nanoTime而不是:旨在为您提供一个相当准确的“挂钟”时间,如果操作系统注意到时钟不同步,则可能会对其进行调整,而专为测量经过的时间而设计自特定时刻以来的时间,与系统时钟的变化无关。System.currentTimeMillisSystem.currentTimeMillisnanoTime

于 2013-07-21T15:49:31.843 回答