5

さまざまな並べ替えアルゴリズムを評価/デモするために、いくつかのJavaクラスを作成しました。しかし、デモクラスを実行すると混乱しました。皆さんが私に説明をしてくれることを願っています。(この質問は宿題ではありません。)

まず、この質問に関連するいくつかのコードをリストします。

AbstractDemo

public abstract class AbstractDemo {
    protected final int BIG_ARRAY_SIZE = 20000;
    protected final int SMALL_ARRAY_SIZE = 14;
    protected Stopwatch stopwatch = new Stopwatch();

    public final void doDemo() {
        prepareDemo();
        specificDemo();
    }

    protected abstract void prepareDemo();

    protected abstract void specificDemo();

    protected final void printInfo(final String text) {
        System.out.println(text);
    }
}

SortingDemo

public class SortingDemo extends AbstractDemo {
    private static final String FMT = "%-10s| %-21s| %7s ms.";
    private static final String SPL = AlgUtil.lineSeparator('-', 45);
    private static final String SPLT = AlgUtil.lineSeparator('=', 45);

    private int[] data;

    private final List<Sorting> demoList = new LinkedList<Sorting>();

    @Override
    protected void specificDemo() {
        int[] testData;
        //*** this comment is interesting!!! for (int x = 1; x < 6; x++) {  

            printInfo(String.format("Sorting %7s elements", data.length));
            printInfo(SPLT);
            for (final Sorting sort : demoList) {

                // here I made a copy of the original Array, avoid to sort an already sorted array.
                testData = new int[data.length];
                System.arraycopy(data, 0, testData, 0, data.length);
                stopwatch.start();
                // sort
                sort.sort(testData);
                stopwatch.stop();
                printInfo(String.format(FMT, sort.getBigO(), sort.getClass().getSimpleName(), stopwatch.read()));
                printInfo(SPL);
                testData = null;
                stopwatch.reset();
            }
        //}
    }

    @Override
    protected void prepareDemo() {
        data = AlgUtil.getRandomIntArray(BIG_ARRAY_SIZE, BIG_ARRAY_SIZE * 5, false);
        demoList.add(new InsertionSort());
        demoList.add(new SelectionSort());
        demoList.add(new BubbleSort());
        demoList.add(new MergeSort());  //here is interesting too
        demoList.add(new OptimizedMergeSort());

    }

    public static void main(final String[] args) {
        final AbstractDemo sortingDemo = new SortingDemo();
        sortingDemo.doDemo();
    }
}

ストップウォッチ

public class Stopwatch {
    private boolean running;
    private long startTime;
    private long elapsedMillisec;

    public void start() {
        if (!running) {
            this.startTime = System.currentTimeMillis();
            running = true;
        } else {
            throw new IllegalStateException("the stopwatch is already running");
        }
    }

    public void stop() {
        if (running) {
            elapsedMillisec = System.currentTimeMillis() - startTime;
            running = false;
        } else {
            throw new IllegalStateException("the stopwatch is not running");
        }
    }

    public void reset() {
        elapsedMillisec = 0;

    }

    public long read() {
        if (running) {
            elapsedMillisec = System.currentTimeMillis() - startTime;
        }
        return this.elapsedMillisec;
    }

}

ランダム配列を生成する方法

public static int[] getRandomIntArray(final int len, final int max, boolean allowNegative) {
        final int[] intArray = new int[len];
        final Random rand = new Random();
        rand.setSeed(20100102);

        if (!allowNegative) {
            if (max <= 0) {
                throw new IllegalArgumentException("max must be possitive if allowNegative false");
            }
            for (int i = 0; i < intArray.length; i++) {
                intArray[i] = rand.nextInt(max);
            }
        } else {
            int n;
            int i = 0;
            while (i < len) {
                n = rand.nextInt();
                if (n < max) {
                    intArray[i] = n;
                    i++;
                }
            }
        }

        return intArray;
    }

ご覧のとおり、20000個の要素を持つint配列を生成します。また、getRandomIntArrayメソッドには固定シードがあるため、呼び出すたびに常に同じ配列があります。クラスSortingDemoにはmainメソッドがあり、このクラスを実行すると、次の出力が得られます。

Sorting   20000 elements
=============================================
O(n^2)    | InsertionSort        |     101 ms.
---------------------------------------------
O(n^2)    | SelectionSort        |     667 ms.
---------------------------------------------
O(n^2)    | BubbleSort           |    1320 ms.
---------------------------------------------
O(nlog(n))| MergeSort            |      39 ms.
---------------------------------------------
O(?)      | OptimizedMergeSort   |      11 ms.
---------------------------------------------

大丈夫そうです。今、私を混乱させた何かが来ます。SortingDemoでdemoList.add()シーケンスを変更した場合、次のように言います。

demoList.add(new InsertionSort());
    demoList.add(new SelectionSort());
    demoList.add(new BubbleSort());
    // OptimizedMergeSort before Mergesort
    demoList.add(new OptimizedMergeSort()); 
    demoList.add(new MergeSort());

私が得た:

Sorting   20000 elements
=============================================
O(n^2)    | InsertionSort        |     103 ms.
---------------------------------------------
O(n^2)    | SelectionSort        |     676 ms.
---------------------------------------------
O(n^2)    | BubbleSort           |    1313 ms.
---------------------------------------------
O(?)      | OptimizedMergeSort   |      41 ms.
---------------------------------------------
O(nlog(n))| MergeSort            |      14 ms.
---------------------------------------------

なぜ出力が最初の実行と異なるのですか?OptimizedMergeSortは通常のMergeSortよりも時間がかかりました...

そしてfor (int x=1; x<6; x++)、SortingDemoの行のコメントを外すと(同じ配列で5回テストを実行します)、次のようになります。

Sorting   20000 elements
=============================================
O(n^2)    | InsertionSort        |     101 ms.
---------------------------------------------
O(n^2)    | SelectionSort        |     668 ms.
---------------------------------------------
O(n^2)    | BubbleSort           |    1311 ms.
---------------------------------------------
O(?)      | OptimizedMergeSort   |      37 ms.
---------------------------------------------
O(nlog(n))| MergeSort            |      10 ms.
---------------------------------------------

Sorting   20000 elements
=============================================
O(n^2)    | InsertionSort        |      94 ms.
---------------------------------------------
O(n^2)    | SelectionSort        |     665 ms.
---------------------------------------------
O(n^2)    | BubbleSort           |    1308 ms.
---------------------------------------------
O(?)      | OptimizedMergeSort   |       5 ms.
---------------------------------------------
O(nlog(n))| MergeSort            |       7 ms.
---------------------------------------------

Sorting   20000 elements
=============================================
O(n^2)    | InsertionSort        |     116 ms.
---------------------------------------------
O(n^2)    | SelectionSort        |     318 ms.
---------------------------------------------
O(n^2)    | BubbleSort           |     969 ms.
---------------------------------------------
O(?)      | OptimizedMergeSort   |       5 ms.
---------------------------------------------
O(nlog(n))| MergeSort            |      10 ms.
---------------------------------------------

Sorting   20000 elements
=============================================
O(n^2)    | InsertionSort        |     116 ms.
---------------------------------------------
O(n^2)    | SelectionSort        |     319 ms.
---------------------------------------------
O(n^2)    | BubbleSort           |     964 ms.
---------------------------------------------
O(?)      | OptimizedMergeSort   |       5 ms.
---------------------------------------------
O(nlog(n))| MergeSort            |       5 ms.
---------------------------------------------

Sorting   20000 elements
=============================================
O(n^2)    | InsertionSort        |     116 ms.
---------------------------------------------
O(n^2)    | SelectionSort        |     320 ms.
---------------------------------------------
O(n^2)    | BubbleSort           |     963 ms.
---------------------------------------------
O(?)      | OptimizedMergeSort   |       4 ms.
---------------------------------------------
O(nlog(n))| MergeSort            |       6 ms.
---------------------------------------------

他の並べ替えの場合、結果は妥当に見えます。しかし、mergeSortの場合、最初の実行に後でよりもはるかに長い時間がかかったのはなぜですか?OptimizedMergeSortの場合は37ms:4ms。

Optimized / MergeSortの実装が間違っていたとしても、出力は同じままである必要があると思います。なぜ、同じメソッド呼び出しに時間がかかる場合と、時間がかかる場合があるのでしょうか。

情報として、これらすべての*Sortクラスは超抽象クラスSortingを拡張します。それは抽象的な方法を持っていますvoid sort(int[] data)

MergeSortにはmergeSortingメソッドとmerge()メソッドがあります。OptimizedMergeSortはMergeSortを拡張し、mergeSorting()メソッドをオーバーライドし(配列サイズ<= 7の場合、insertionSortを実行するため)、クラスmerge()からメソッドを再利用します。MergeSort

この長いテキストとコードを読んでいただきありがとうございます。皆さんが私にいくつかの説明をしてくれれば幸いです。

すべてのテストは、LinuxのEclipseで実行されました。

4

3 に答える 3

4

Javaコードのマイクロベンチマークは、トリッキーなことで有名です。

ジャストインタイムコンパイラが、Javaバイトコードをネイティブマシンコードにコンパイルするために、ある時点で起動する可能性が非常に高くなります。すべてのコンパイルには時間がかかりますが、結果のコードはより高速に実行される可能性があります。

他にも落とし穴がありますが、あなたの場合は上記が最も可能性が高いと思います。

次のSOの答えは非常に良い読み物です:https ://stackoverflow.com/a/513259/367273

于 2011-12-03T17:28:11.260 に答える
1

基本的に、考えられる理由は2つあります。どちらも、プログラムではなく環境に関連しています。他の何かが多くのスペースを占有したか、他の何かが多くのCPU時間を消費したかです。

最初のケースでは、物理メモリを消費する他のプログラムがあり、プログラムのページングやガベージコレクションが頻繁に発生します。

2つ目は、他のプログラム(Macを実行している場合は、Time Machineに賭けます)が断続的に実行され、CPUを消費します。

いずれにせよ、あなたが見つけることができる方法は、Javaに付属しているツールを使い始めることです。jconsoleとVirtualVMは良い可能性です。

一般に、パフォーマンスの問題が発生した場合は、測定、測定、および測定の3つの重要な手順を実行する必要があります。

アップデート

JITが違いを生む可能性があることに同意しますが、私が得た印象は、これらは別々の実行であるということです。毎回新しいJVMを呼び出しています。これにより、JITの影響が最小限に抑えられます。

于 2011-12-03T17:24:34.747 に答える
0

JITの影響を減らすために、各テストの最初の数回の実行を破棄できます。また、より正確な結果を得るには、平均で100回または1000回以上実行します。

測定を開始する前に、System.gc()およびThread.yeild()を実行することもできます。数回の反復のみをテストする場合は、system.nanoTime()を優先し、system.currentTimeMillisを使用しないでください(十分に正確ではありません)。

于 2011-12-03T17:52:23.963 に答える