Java8 の Arrays.parallelSort() を試してみた

Java8 では Arrays.parallelSort() が導入される予定だ。

どうやら Fork/Join Framework を使っているようです。

今まではプリミティブ型はデュアルピボットのクイックソートで参照型は Tim ソートだったような記憶があります。

この記憶の信憑性はかなり低いので間違っていても怒らないでくださいね(^_^;)

そこで早速試してみることにします。

コードはシンプルなソートです。

jp\yucchi\parallelsort\ParallelSort.java
package jp.yucchi.parallelsort;

import java.util.Arrays;
import java.util.Date;
import java.util.Random;

public class ParallelSort {

    private static final int TARGET_SIZE = 500_000_000;
    private static final int LOOP_SIZE = 20;
    private static long startTime;
    private static long time;
    private static long avgTime;
    private static long sumTime;
    private static int count;
    private static long avg4p;

    public static void main(String[] args) {
        Random random = new Random(new Date().getTime());
        int[] source = new int[TARGET_SIZE];
        int[] copy;
        for (int i = 0; i < TARGET_SIZE; ++i) {
            source[i] = random.nextInt(TARGET_SIZE);
        }
        for (int i = 0; i < LOOP_SIZE; ++i) {
            copy = Arrays.copyOfRange(source, 0, TARGET_SIZE);
            startTime = System.nanoTime();
            Arrays.parallelSort(copy);
            time = System.nanoTime() - startTime;
            System.out.println(i + 1 + "回目 : Arrays.parallelSortの処理時間は、"
                    + (int) (time * 1e-9) / 3_600 + "時間"
                    + (int) ((time * 1e-9) / 60) % 60 + "分"
                    + (int) (time * 1e-9 % 60) + "秒"
                    + Double.toString((time * 1e-9 % 60) % 1).substring(2) + "\n");
            if (i > 9) {
                sumTime += time;
                count++;
            }
        }
        avgTime = sumTime / count;
        System.out.println("<----- Arrays.parallelSortの平均処理時間は、"
                + (int) (avgTime * 1e-9) / 3_600 + "時間"
                + (int) ((avgTime * 1e-9) / 60) % 60 + "分"
                + (int) (avgTime * 1e-9 % 60) + "秒"
                + Double.toString((avgTime * 1e-9 % 60) % 1).substring(2) + " ----->\n");
        avgTime = 0;
        count = 0;
        sumTime = 0;

        for (int i = 0; i < LOOP_SIZE; ++i) {
            copy = Arrays.copyOfRange(source, 0, TARGET_SIZE);
            startTime = System.nanoTime();
            Arrays.sort(copy);
            time = System.nanoTime() - startTime;
            System.out.println(i + 1 + "回目 : Arrays.sortの処理時間は、"
                    + (int) (time * 1e-9) / 3_600 + "時間"
                    + (int) ((time * 1e-9) / 60) % 60 + "分"
                    + (int) (time * 1e-9 % 60) + "秒"
                    + Double.toString((time * 1e-9 % 60) % 1).substring(2) + "\n");
            if (i > 9) {
                sumTime += time;
                count++;
            }
        }
        avgTime = sumTime / count;
        System.out.println("<----- Arrays.sortの平均処理時間は、"
                + (int) (avgTime * 1e-9) / 3_600 + "時間"
                + (int) ((avgTime * 1e-9) / 60) % 60 + "分"
                + (int) (avgTime * 1e-9 % 60) + "秒"
                + Double.toString((avgTime * 1e-9 % 60) % 1).substring(2) + " ----->\n");

    }

}


全てのソート時間の取得と表示、そして11回目からのソート処理平均時間の取得と表示をそれぞれ

Arrays.parallelSort() と Arrays.sort() で実行してます。

このプログラムの実行結果は概ね予測できますが下記に実行結果を貼っておきます。

1回目 : Arrays.parallelSortの処理時間は、0時間0分4秒4152691810000002

2回目 : Arrays.parallelSortの処理時間は、0時間0分3秒1656751470000004

3回目 : Arrays.parallelSortの処理時間は、0時間0分3秒4398564410000003

4回目 : Arrays.parallelSortの処理時間は、0時間0分3秒18688716800000016

5回目 : Arrays.parallelSortの処理時間は、0時間0分3秒4902016290000004

6回目 : Arrays.parallelSortの処理時間は、0時間0分3秒1557479500000003

7回目 : Arrays.parallelSortの処理時間は、0時間0分3秒5248610990000002

8回目 : Arrays.parallelSortの処理時間は、0時間0分3秒21521467700000008

9回目 : Arrays.parallelSortの処理時間は、0時間0分3秒4352946820000003

10回目 : Arrays.parallelSortの処理時間は、0時間0分3秒176553014

11回目 : Arrays.parallelSortの処理時間は、0時間0分3秒5098383400000004

12回目 : Arrays.parallelSortの処理時間は、0時間0分3秒2292058370000003

13回目 : Arrays.parallelSortの処理時間は、0時間0分3秒4357429300000004

14回目 : Arrays.parallelSortの処理時間は、0時間0分3秒20676435400000015

15回目 : Arrays.parallelSortの処理時間は、0時間0分3秒45285167800000004

16回目 : Arrays.parallelSortの処理時間は、0時間0分3秒2242083810000004

17回目 : Arrays.parallelSortの処理時間は、0時間0分3秒4621416820000004

18回目 : Arrays.parallelSortの処理時間は、0時間0分3秒5754989530000003

19回目 : Arrays.parallelSortの処理時間は、0時間0分3秒500453534

20回目 : Arrays.parallelSortの処理時間は、0時間0分3秒21473901200000034

<—– Arrays.parallelSortの平均処理時間は、0時間0分3秒3811444700000002 —–>

1回目 : Arrays.sortの処理時間は、0時間0分48秒9387049350000041

2回目 : Arrays.sortの処理時間は、0時間0分48秒9633070610000019

3回目 : Arrays.sortの処理時間は、0時間0分49秒015938085000001934

4回目 : Arrays.sortの処理時間は、0時間0分48秒9707528720000056

5回目 : Arrays.sortの処理時間は、0時間0分49秒2902336700000063

6回目 : Arrays.sortの処理時間は、0時間0分48秒9888089870000059

7回目 : Arrays.sortの処理時間は、0時間0分48秒9633770900000016

8回目 : Arrays.sortの処理時間は、0時間0分48秒9997757110000052

9回目 : Arrays.sortの処理時間は、0時間0分48秒9295900030000013

10回目 : Arrays.sortの処理時間は、0時間0分49秒08955452700000421

11回目 : Arrays.sortの処理時間は、0時間0分50秒13118777600000442

12回目 : Arrays.sortの処理時間は、0時間0分49秒8455564950000038

13回目 : Arrays.sortの処理時間は、0時間0分49秒24517728500000402

14回目 : Arrays.sortの処理時間は、0時間0分49秒12246824000000345

15回目 : Arrays.sortの処理時間は、0時間0分48秒901129044000001

16回目 : Arrays.sortの処理時間は、0時間0分49秒40450923900000646

17回目 : Arrays.sortの処理時間は、0時間0分50秒7024559510000046

18回目 : Arrays.sortの処理時間は、0時間0分49秒7857455720000033

19回目 : Arrays.sortの処理時間は、0時間0分50秒1460985550000018

20回目 : Arrays.sortの処理時間は、0時間0分51秒37098508900000127

<—– Arrays.sortの平均処理時間は、0時間0分49秒8655313240000027 —–>

Arrays.parallelSort() が3秒前半のスコアに対して Arrays.sort() は、ほぼ 50 秒かかってます。

予想通り Arrays.parallelSort() が圧倒的に高速ですね。(^_^)

その秘密は NetBeans のプロファイラで確認しました。

内部で Fork/Join Framework が使われてるのが確認されました。

1

Java は並行処理を簡単に実行できるようにいろいろがんばって作られてるようです。

ちなみに、アレイのサイズを21億個まで増大させたときのプログラムの実行結果は次のようになりました。

1回目 : Arrays.parallelSortの処理時間は、0時間0分26秒7820320810000005

2回目 : Arrays.parallelSortの処理時間は、0時間0分14秒215850219

3回目 : Arrays.parallelSortの処理時間は、0時間0分15秒21248125400000006

4回目 : Arrays.parallelSortの処理時間は、0時間0分14秒17695699800000142

5回目 : Arrays.parallelSortの処理時間は、0時間0分15秒21644380900000115

6回目 : Arrays.parallelSortの処理時間は、0時間0分14秒13889982600000117

7回目 : Arrays.parallelSortの処理時間は、0時間0分15秒3859477300000016

8回目 : Arrays.parallelSortの処理時間は、0時間0分14秒15733845600000151

9回目 : Arrays.parallelSortの処理時間は、0時間0分15秒042537343000001115

10回目 : Arrays.parallelSortの処理時間は、0時間0分14秒10847939100000126

11回目 : Arrays.parallelSortの処理時間は、0時間0分15秒31738622100000136

12回目 : Arrays.parallelSortの処理時間は、0時間0分14秒09331228100000111

13回目 : Arrays.parallelSortの処理時間は、0時間0分15秒23933288000000097

14回目 : Arrays.parallelSortの処理時間は、0時間0分14秒09788163900000058

15回目 : Arrays.parallelSortの処理時間は、0時間0分15秒2869010420000002

16回目 : Arrays.parallelSortの処理時間は、0時間0分14秒1130110920000007

17回目 : Arrays.parallelSortの処理時間は、0時間0分15秒037243257000000085

18回目 : Arrays.parallelSortの処理時間は、0時間0分14秒1627590560000005

19回目 : Arrays.parallelSortの処理時間は、0時間0分15秒16421842200000114

20回目 : Arrays.parallelSortの処理時間は、0時間0分14秒3338693370000012

<—– Arrays.parallelSortの平均処理時間は、0時間0分14秒6845915220000016 —–>

1回目 : Arrays.sortの処理時間は、0時間3分46秒10638811700002293

2回目 : Arrays.sortの処理時間は、0時間3分45秒5415704870000013

3回目 : Arrays.sortの処理時間は、0時間3分44秒14708787200001439

4回目 : Arrays.sortの処理時間は、0時間3分44秒28659846600001515

5回目 : Arrays.sortの処理時間は、0時間3分44秒2646577520000051

6回目 : Arrays.sortの処理時間は、0時間3分43秒6922063590000107

7回目 : Arrays.sortの処理時間は、0時間3分43秒25756076300001496

8回目 : Arrays.sortの処理時間は、0時間3分44秒48740214200000764

9回目 : Arrays.sortの処理時間は、0時間3分42秒6569463620000136

10回目 : Arrays.sortの処理時間は、0時間3分42秒32911070500000505

11回目 : Arrays.sortの処理時間は、0時間3分41秒22716906600001607

12回目 : Arrays.sortの処理時間は、0時間3分41秒819911870000027

13回目 : Arrays.sortの処理時間は、0時間3分41秒3822147500000028

14回目 : Arrays.sortの処理時間は、0時間3分41秒0946705690000158

15回目 : Arrays.sortの処理時間は、0時間3分42秒02558318500001633

16回目 : Arrays.sortの処理時間は、0時間3分51秒4318844270000284

17回目 : Arrays.sortの処理時間は、0時間3分52秒048210971000003155

18回目 : Arrays.sortの処理時間は、0時間3分52秒01929548700002215

19回目 : Arrays.sortの処理時間は、0時間3分52秒04963036800000964

20回目 : Arrays.sortの処理時間は、0時間3分52秒09709150600002658

<—– Arrays.sortの平均処理時間は、0時間3分46秒7195662190000007 —–>

Java8 の正式リリースが待ち遠しいです!

ちなみに 9 月 9 日にリリース予定だったのですが、どうやら遅れそうです。

ツイッター上では 2014 年になるとか・・・つぶやかれていました。

今のうちにもっと情報集めて Java8 をしっかり楽しめるようにがんばってみるとしよう。(*^o^*)

Hatena タグ:

 

もっと Lambda その3

今日も Java8 の新機能に慣れるべくいつものようにネットサーフィンで得た情報を試してみます。

今回は前回チラッと現れたSupplier インターフェイスと Constructor References をためしてみようと思います。

非常に簡単でシンプルな内容なのです。ラムダ式を使う方法とコンストラクターリファレンスを使う方法を記述してます。

それを Supplier インターフェイスの get() メソッドで取得してそれぞれのインスタンスメソッドを実行させているだけです。

特に難しいところは無さそうですが、この使い分けのシチュエーションは微妙かもしれませんね。

では、プログラムのコードです。

mylambdaexamples_3\Airplane.java
package mylambdaexamples_3;

class Airplane {

    void pilot() {
        System.out.println("飛行機を操縦します。");
    }

}
 

mylambdaexamples_3\JetAirplane.java
package mylambdaexamples_3;

class JetAirplane extends Airplane {

    @Override
    void pilot() {
        System.out.println("ジェット機を操縦します。");
    }

}

mylambdaexamples_3\MyLambdaExamples_3.java
package mylambdaexamples_3;

import java.util.function.Supplier;

public class MyLambdaExamples_3 {

    public static void main(String[] args) {
        // Lambda Expression
        pilot(() -> new Airplane());
        pilot(() -> new JetAirplane());
        // Constructor References
        pilot(Airplane::new);
        pilot(JetAirplane::new);
    }

    static void pilot(Supplier supplier) {
        Airplane airPlane = supplier.get();
        airPlane.pilot();
    }

}
 

実行結果は次のようになります。

飛行機を操縦します。
ジェット機を操縦します。
飛行機を操縦します。
ジェット機を操縦します。

Java の学習の初めのころにこのような感じのをやったようなデジャブを感じます。

いちおう JavaDoc をサラッと見てみます。

いつものように優秀な翻訳支援ソフトに活躍してもらいます。(>_<。)

 

Supplier

java.​util.​function

@FunctionalInterface
public interface Supplier<T>

A supplier of objects. The result objects are either created during the invocation of Supplier.get or by some prior action.

パラメータ:

T – The type of objects returned by get

日付:

1.8

オブジェクトのサプライヤ。 オブジェクトが Supplier.get の呼出しの間に、あるいは若干の事前のアクションによってあるいは作り出されるという結果。

パラメータ: get によりオブジェクトのタイプが返される。

 

get()

java.​util.​function.​Supplier

public T get()

Returns an object.

戻り値:

an object

オブジェクトを返します。

 

特に難しいところは無さそうですね。強いて言うなら英語の JavaDoc か・・・

そういうことでそろそろお約束の時間です。

この「もっと Lambda 」シリーズは、インターネット上で得た情報を元にそれを少し変更しているだけです。

悲しいことにその情報源は英語なので詳しい内容はわかりません。

よって私の推測で解釈された内容となってますので間違いがあると思います。

Java8 もまだ build86 を使用していますので API の変更により記述方法が変わるかもしれません。

早く正式リリースされて日本語でこの超便利で素敵な新機能を勉強したい今日この頃です。

 

Hatena タグ: