omp4jによる並列化

Pythonで並列化させたプログラムを走らせていたのですがあまりの遅さにJavaへと変更した際、並列化をomp4jで簡単にできたのでメモ。

omp4j

OpenMPの説明は、Wikipediaをみてもらうことにして、ソースコード中にコメントを書いておいて、コンパイルをすれば並列化プログラムの出来上がるという便利なライブラリ。

ここからJarファイルをダウンロードします。

wget https://github.com/omp4j/omp4j/releases/download/v1.2/omp4j-1.2.jar

Javaプログラム

簡単なプログラムを作成します。スレッド5で10回計算しています。


import java.util.Random;


public class OmpTest {
        private void run() {
                try {
                        // omp parallel for threadNum(5)
                        for (int i = 0; i < 10; i++) {
                                new Task1(i).call();
                        }

                } finally {
                        System.out.println("ThreadTest:finish");

                }
        }

        static class Task1{
                private int number;
                Task1(int number){
                        this.number=number;

                }
                public Long call()  {
                        System.out.println("Task1.start:"+this.number);
                        long sleep=new Random().nextInt(10)*1000;
                        long sum = 0;
                        for (int i = 1; i <= 100 * 10000; i++) {
                                sum += i;
                        }
                        try{
                                Thread.sleep(sleep);
                        }catch(Exception e){}
                        System.out.println("Task1.end:"+this.number+",sleep="+sleep);
                        return sum;
                }
        }

        public static void main(String[] argv){
                new OmpTest().run();
        }
}

シングルスレッド

普通にコンパイルします。シングルスレッドで動作します。


$ javac OmpTest.java
$ java OmpTest
Task1.start:0
Task1.end:0,sleep=3000
Task1.start:1
Task1.end:1,sleep=2000
Task1.start:2
Task1.end:2,sleep=1000
Task1.start:3
Task1.end:3,sleep=0
Task1.start:4
Task1.end:4,sleep=5000
Task1.start:5
Task1.end:5,sleep=6000
Task1.start:6
Task1.end:6,sleep=9000
Task1.start:7
Task1.end:7,sleep=3000
Task1.start:8
Task1.end:8,sleep=8000
Task1.start:9
Task1.end:9,sleep=2000
ThreadTest:finish

シリアルに計算されているのがわかります。

マルチスレッド

並列化できるようにコンパイルします。


$ java -jar omp4j-1.2.jar OmpTest.java
$ java OmpTest
Task1.start:3
Task1.start:1
Task1.start:2
Task1.start:4
Task1.start:0
Task1.end:1,sleep=0
Task1.start:5
Task1.end:0,sleep=3000
Task1.start:6
Task1.end:2,sleep=3000
Task1.end:5,sleep=3000
Task1.start:7
Task1.start:8
Task1.end:3,sleep=4000
Task1.start:9
Task1.end:4,sleep=7000
Task1.end:9,sleep=3000
Task1.end:6,sleep=8000
Task1.end:8,sleep=8000
Task1.end:7,sleep=9000
ThreadTest:finish

並列に計算できているのがわかります。
実際にはコンパイル時にコードを変換してコンパイルしています。
ここにソースコードを貼り付けると変換後のソースが表示されます。上記サンプルだとエラーになってしまいましたが、簡単なコードならばそのコードが表示されます。

まとめ

簡単にJavaのコードが並列化できます。色々と制約はありますが(変数関連など)、簡単に並列プログラムが作成できるのはメリットでしょう。