無料で使えるシステムトレードフレームワーク「Jiji」 をリリースしました!

・OANDA Trade APIを利用した、オープンソースのシステムトレードフレームワークです。
・自分だけの取引アルゴリズムで、誰でも、いますぐ、かんたんに、自動取引を開始できます。

EnumMapがどれだけ早いか性能を測ってみた。

EnumMapとかいうEnumのみをキーにできるMapがあって、これがEnumの連番を使って高速に動作するらしい。(→Java プログラミング言語 - 列挙型)
ということでとりあえず性能を測ってみた。

計測方法

  • EnumをキーとしたMapのインスタンスをいろいろ作成し、
  • get、putをそれぞれ500000*26回実行した場合の所要時間を計測。
  • それぞれ5回試行し、平均を取る。

結果

get put
EnumMap 312ms 490ms
HashMap 593ms 921ms
TreeMap 334ms 1490ms
LinkedHashMap 497ms 690ms

うん、まぁ、早いかな。> EnumMap
なお、計測環境のCPUは Pentium D 2.79GHz, JDKは1.6.0_07です。

計測で使用したコード

計測で使用したコードは以下の通り。

// テスト用の列挙型
enum Test {
    A, B, C, D, E, F, G, H, I, J,
    K, L, M, N, O, P, Q, R, S, T,
    U, V, W, X, Y, Z
}
・・・
// EnumMap
final Map<Test, String> enumMap =
    new EnumMap<Test, String>(Test.class);
for ( Test t : Test.values() ) enumMap.put( t, t.name());

// HashMap
final Map<Test, String> map =
    new HashMap<Test, String>(Test.values().length);
for ( Test t : Test.values() ) map.put( t, t.name());

// TreeMap
final Map<Test, String> treeMap =
    new TreeMap<Test, String>();
for ( Test t : Test.values() ) treeMap.put( t, t.name());

// LinkedHashMap
final Map<Test, String> linkedMap =
    new LinkedHashMap<Test, String>(Test.values().length);
for ( Test t : Test.values() ) linkedMap.put( t, t.name());


// Mapからの取り出し処理
class GetTask extends Perf.Task<Void> {
    final Map<Test, String> map;
    GetTask( Map<Test, String> map ) { this.map = map; }
    @Override
    public Void run(int i) {
        for ( int j = 0; j < 500000; j++ ) {
            for ( Test t : Test.values() ) {
                map.get( t );
            }
        }
        return null;
    }
}
System.out.println( Perf.perf( "get-EnumMap", 5, new GetTask( enumMap ) ) );
System.out.println( Perf.perf( "get-HashMap", 5, new GetTask( map ) ) );
System.out.println( Perf.perf( "get-TreeMap", 5, new GetTask( treeMap ) ) );
System.out.println( Perf.perf( "get-LinkedHashMap", 5, new GetTask( linkedMap ) ) );

// Mapへの登録処理
class PutTask extends Perf.Task<Void> {
    final Map<Test, String> map;
    PutTask( Map<Test, String> map ) { this.map = map; }
    @Override
    public Void run(int i) {
        for ( int j = 0; j < 500000; j++ ) {
            for ( Test t : Test.values() ) {
                map.put( t, t.name() );
            }
        }
        return null;
    }
}
System.out.println( Perf.perf( "put-EnumMap", 5, new PutTask( enumMap ) ) );
System.out.println( Perf.perf( "put-HashMap", 5, new PutTask( map ) ) );
System.out.println( Perf.perf( "put-TreeMap", 5, new PutTask( treeMap ) ) );
System.out.println( Perf.perf( "put-LinkedHashMap", 5, new PutTask( linkedMap ) ) );

Perf.javaは以下です。

import java.util.ArrayList;
import java.util.List;

/**
 * 性能計測ユーティリティ
 */
public class Perf {

    /**
     * 処理の実行時間を計る
     * @param <R> 戻り値の型
     * @param id 識別子
     * @param count 試行回数
     * @param task 処理
     * @return 計測結果
     * @throws Exception
     */
    public static <R> Result<R> perf ( String id, int count, Task<R> task )
    throws Exception {

        // 初回のクラスロード時間を抑制するため
        // 1度実行する
        task.before(-1);
        R result = task.run(-1);
        task.after(-1);

        List<Long> times = new ArrayList<Long>();
        for ( int i = 0 ; i < count ; i++  ) {
          task.before(i);
          long start = System.currentTimeMillis();
          task.run(i);
          times.add(System.currentTimeMillis() - start);
          task.after(i);
        }
        return new Result<R>( id, result, times );
    }

    /**
     * 計測結果
     *
     * @param <R> 戻り値の型
     *
     * @version $Revision:$
     * @author  $Author:$
     */
    public static class Result<R> {

        /**
         * 結果
         */
        public R result;

        /**
         * ID
         */
        public String id;

        /**
         * 最大
         */
        public long max;

        /**
         * 最小
         */
        public long min;

        /**
         * 平均
         */
        public long avg;

        /**
         * 処理時間
         */
        public List<Long> times;

        /**
         * コンストラクタ
         * @param id ID
         * @param result 結果
         * @param times 処理時間
         */
        public Result ( String id, R result, List<Long> times ) {
            this.result = result;
            this.times = times;
            this.id = id;
            long sum = 0;
            max = Long.MIN_VALUE;
            min = Long.MAX_VALUE;
            for ( long l : times ) {
                max = Math.max( max, l );
                min = Math.min( min, l );
                sum += l;
            }
            avg = sum / times.size();
        }

        public String toString () {
            StringBuilder str = new StringBuilder();
            str.append( "---" ).append( id ).append( "\n" );
            str.append( avg ).append( ", " ).append( max ).append( ", " )
                .append( min ).append( " [ " );
            for ( long l : times ) {
                str.append( l ).append( " " );
            }
            str.append( "]" );
            return str.toString();
        }
    }

    /**
     * 計測する処理
     *
     * @param <R> 戻り値の型
     *
     */
    public static class Task<R> {
        /**
         * 処理の実行前に呼び出される
         * @param i 試行番号
         * @throws Exception
         */
        public void before ( int i ) throws Exception {}
        /**
         * 処理の実行後に呼び出される
         * @param i 試行番号
         * @throws Exception
         */
        public void after ( int i ) throws Exception {}
        /**
         * 計測する処理
         * @param i 試行番号
         * @return 結果
         * @throws Exception
         */
        public R run ( int i ) throws Exception {
            return null;
        }
    }
}