kobaPod

てきとうなメモ書き

今更ながらFork/Joinフレームワークを使ってみた

[java][paiza]PaizaのAランクに挑戦しました。

気が乗ったときに行っているPaizaですが、
先日Aランクに挑戦しました、が
大規模データのテストケースで実行タイムオーバーになってしまったこと。

そういえば今まで大規模データを扱って、並列処理とかしたことがなかったなぁ、ってことで
簡単なFork/Joinフレームワークで並列処理を試してみた。

Fork/Joinフレームワークを使ってみる。

1からintの最大値-1までを計算するよう、以下の処理を作成。
まずは素直に与えられたパラメータ(From~To)を順に計算していく単純なプログラム。
与えるパラメータは以下の通り
rangeFrom : 1
rangeTo : intの最大値-1 (2147483646)

SimpleCalculate
package fork_join;

public class SimpleCalculate {
 public long calculate(int rangeFrom, int rangeTo) {
  
  long sum = 0;
  for (int i = rangeFrom; i <= rangeTo; i++) {
   sum += i;
  }
  return sum;
 }
}


続いて、計算対象が一定数を超える場合にFork/Joinによる並列処理を行う。

ForkCalculate
package fork_join;

import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;

public class ForkCalculate {
 public long calculate(int rangeFrom, int rangeTo){
  
  ForkJoinPool pool = new ForkJoinPool();
  MyTask task = new ForkCalculate().new MyTask(rangeFrom, rangeTo);
  pool.execute(task);
  
  return task.join();
 }
 
 
 public class MyTask extends RecursiveTask<Long>{
  final int start;
  final int end;
  final static int FORK_LIMIT = 100000; //処理分割の閾値(計算対象件数がこれを上回る場合処理分割)

  public MyTask(int start, int end) {
   this.start = start;
   this.end = end;
  }
  @Override
  protected Long compute() {
   int calcNum = end - start;
   int half = calcNum / 2;
   //計算対象が閾値を上回る場合、処理を分割
   if(calcNum > FORK_LIMIT){
    MyTask task1 = new MyTask(start, start+half);
    task1.fork();
    MyTask task2 = new MyTask(start + half+1, end);
    return task2.compute() + task1.join();
   }
   //閾値を下回る場合は、そのまま計算
   else{
    long sum = 0;
    for(int i = start; i <= end; i++){
     sum += i;
    }
    return sum;
   }
  }
 }
}

ちなみに実行結果は...
メソッド名 処理時間
SimpleCalculate#calculate 1764.6537ms
ForkCalculate#calculate 676.5478ms

一応実行速度てきには1/3近くにはなったが、
それでも0.7秒程かかってしまっている。

Fork/Joinの使い方が誤っているのか、
それとも他に正しいやり方があるのか。。。

とりあえず、現状ここまでとしておこう。