ÖNEMLİ : Kendim için aldığım notlar. Umarım size de bir faydası olur. Kullanılan her bir makale referans olarak eklenmiştir. Rice Üniversitesi’nin hazırladığı eğitsel bir Framework olan PCDP bu ve sonraki bölümlerde kullanılacaktır. async ve finish notasyonları bu Framework’de yer almaktadır.

Java Paralel Programlama Serisi


  1. Java Paralel Programlama - Bölüm 1
  2. Java Paralel Programlama - Bölüm 2
  3. Java Paralel Programlama - Bölüm 3
  4. Java Paralel Programlama - Bölüm 4

Genel Bakış

Bir önceki bölümde gördüğümüz async ve finish notasyonları eğitsel ve gösterimsel kavramlardı. Fakat Java’daki karşılıkları tabii ki bu şekilde değildir. Bu bölümde ise aynı konseptin Java’daki karşılıklarına bakacağız. Java’da çok çekirdekli paralellikten yararlanmanın en popüler yollarından biri olan Java Fork/Join Framework‘üdür.

Öyleyse array-sum örneğimize geri dönelim. Ve önce bir “böl ve fethet algoritmasına” kadar uzatabilir miyiz bir bakalım. Şimdi, daha nesne odaklı düşünelim ve bir sınıfımız olduğunu söyleyelim. Bu sınıfımızın adı ASUM olsun.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
CLASS ASUM {
  A, // an array
  LO, // lower bound
  UP, // upper bound
  SUM;
  //compute() metodu, aslında alt ve üst sınırlar ve
  //array göz önüne alındığında toplamı hesaplayacak
  //bir hesaplama yöntemimizdir.
  COMPUTE(){  
    // Örneğin, eğer LO, UP ile aynıysa, sum değerini
    //array LO'ya ata, ki set high ile aynı yaparız.
    IF(LO == UP) SUM = A[LO];
    ELSE IF (LO>UP) SUM = 0;
    ELSE {
      MID = (LO+UP)/2;
      L = NEW ASUM(A,LO,MID);
      R = NEW ASUM(A,MID+1,UP);
      L.COMPUTE();
      R.COMPUTE();
      SUM = L.SUM + R.SUM;
    }
  }
}

Hatırlatma


Bu bölümde, async, finish ve Fork/Join kavramlarını deneysel anlatmak için böl ve fethet algoritması(divide and conquer algorithm) kullanılacaktır. Bu algoritmanın arkasındaki temel fikir, sorunu ikiye bölmektir. Amacımız algoritmanın detayına girmek değil. Temel hedefimiz, bu algoritmayı nasıl paralel hale getirebiliriz? Algoritma ile ilgili daha detaylı bilgiye ulaşmak için bu linki ziyaret edebilirsiniz.

Yukarıda görüleceği üzere L.COMPUTE() ve R.COMPUTE() olarak ifade edilmiş 2 işlem bulunmaktadır. Biz bu işlemlerden herhangi birini, örneğin L.COMPUTE() olanı asenkron olarak işaretlersek paralellik sağlamış oluruz. finish notasyonu ile de bu iki işlemi bir kapsam içine alırsak, iki işlemin nihayete ereceği garanti altına alınmış olur. Böylelikle iki işlem bitmeden SUM işlemine geçilemez.

1
2
3
4
5
FINISH {
  ASYNC L.COMPUTE() // L.FORK async ile aynı işi yapar.
        R.COMPUTE()
}
SUM = L.SUM + R.SUM;

finish ise join ile aynı işi yapar. Tek fark, finish scope içindeki bütün işlerin bitmesini beklerken, join sadece bir işe odaklanır. Benzer işlem async ve finish notasyonları yerine fork/join kullanılarak ise şu şekilde yapılır.

1
2
3
4
5
L.COMPUTE();
L.FORK;
R.COMPUTE()
L.JOIN();
SUM = L.SUM + R.SUM;

Fork/Join görevleri, java iş parçacığı havuzu olan bir “ForkJoinPool” içinde yürütülür. Bu havuz, hem fork hem de join işlemlerini paralel bir dizi görevi yürüterek ve bunların tamamlanmasını bekleyerek birleştiren invokeAll() yöntemini destekler. Örneğin, ForkJoinTask.invokeAll (sol, sağ), örtülü olarak sol ve sağda fork() işlemlerini gerçekleştirir, ardından her iki nesnede de join() işlemi gerçekleştirir.

Bu Framework’de, kullanıcının kendi oluşturacağı bir sınıf, FJ Framework‘ü içinde bulunan RecursiveAction sınıfı extends edilip, bu sınıfın yerleşik metodlarından biri olan compute() metodu override edildikten sonra, metodun içinde istenilen görev belirlenebilir.

1
2
3
4
5
6
7
8
9
10
11
12
private static class ASum extends RecursiveAction {
  int[] A; // input array
  int LO, HI; // subrange
  int SUM; // return value
  ...

  @Override
  protected void compute() {
    SUM = 0;
    for (int i = LO; i <= HI; i++) SUM += A[i];
  } // compute()
}

Referanslar :

  1. Sequential algorithm
  2. Asynchronous method invocation
  3. Analysis of parallel algorithms
  4. Class RecursiveAction
  5. Class RecursiveTask
  6. Class ForkJoinPool
  7. Package java.util.stream
  8. Interface Stream
  9. Fork/Join
  10. Java VisualVM
  11. Parallel Programming in Java
  12. PCDP parallel programming framework