Bölüm 10: Paralel Algoritmalar

Algoritmalar
Neden paralellik?Flynn ve PRAM modelleriHızlanma, Amdahlİş ve derinlik PRAM ile toplamaÖnek toplamıBoru hattıBoru hatlı ağaçFork/Join, MapReduce
Sercan KÜLCÜ · Giresun Üniversitesi · Bilgisayar Mühendisliği

Giriş

Öğrenme Çıktıları

Kavramlar

Paralel algoritmanın böl–ata–birleştir yapısını, avantaj ve zorluklarını (iletişim, senkronizasyon, yük dengeleme) açıklamak.

Modeller ve ölçütler

Flynn sınıflarını ve PRAM modelini tanımak; hızlanma, verim, maliyet, iş ve derinliği hesaplamak; Amdahl yasasını uygulamak.

Temel teknikler

PRAM ağaç toplamını, paralel önek toplamını, boru hattını ve boru hatlı ağacı adım adım yürütmek ve adım sayılarını bulmak.

Java'da paralellik

Fork/Join ile paralel birleştirme sıralaması, MapReduce ve veri paralelliği örneklerini okumak; yarış durumlarını fark etmek.

Giriş

Birlikte Daha Hızlı

  • Bazı işleri bitirmek için çok fazla zaman gerekir: büyük veri analizi, bilimsel simülasyon, görüntü işleme.
  • Paralel algoritmalar (parallel algorithms) bir problemi aynı anda birden fazla işlemci (çekirdek) kullanarak çözer.
  • Karmaşık görevler çok daha kısa sürede tamamlanabilir.
  • Tek çekirdeğin saat hızı artık neredeyse artmıyor; performans artışı çekirdek sayısından geliyor.
Benzetme: 1000 sınav kâğıdını bir öğretmen 10 saatte okur. 10 öğretmen kâğıtları paylaşırsa ≈ 1 saat sürer; ama kâğıtları dağıtmak ve notları toplamak da zaman alır.

Giriş

Paralel Algoritmalar

  • Bir grup insanın birlikte çalışmasına benzer.
  • Karmaşık problemi daha küçük parçalara ayırır.
  • Parçaları aynı anda farklı işlemcilere atayarak işi hızlandırır.
  • İşlemciler görevlerini bitirince sonuçlar birleştirilir.
  • Yüksek başarımlı hesaplamanın (HPC) temelidir.
  • Büyük veri analizi, bilimsel simülasyon, makine öğrenmesi gibi alanlarda kullanılır.
Problemparça 1p₁parça 2p₂parça 3p₃parça 4p₄Sonuç

Giriş

Dezavantajlar ve Zorluklar

Kazanımlar

  • Aynı işi daha kısa sürede bitirmek (hızlanma)
  • Tek makineye sığmayan büyük problemleri çözebilmek (ölçeklenebilirlik)
  • Donanımı (tüm çekirdekleri, GPU'yu) verimli kullanmak

Dezavantajlar

  • Problemi parçalara ayırmak ve birleştirmek ek çaba gerektirir
  • İletişim ve senkronizasyon ek yük getirir
  • Yük dengeleme: tüm işlemcilere eşit iş düşmeli, yeterli işlem gücü olmalı
  • Hata ayıklama zordur (yarış durumu, kilitlenme)
  • Bazı problemler yapısı gereği sıralıdır
Veri bağımlılığı varsa (adım k, adım k − 1'in sonucunu bekliyorsa) o kısım paralelleştirilemez: örn. xₖ = f(xₖ₋₁) yinelemesi.

Giriş

Uygulama Alanları

Matris çarpımı

Bilimsel hesaplamanın temel işlemi; sonuç matrisinin her satırı (hatta her hücresi) bağımsız hesaplanabilir.

Görüntü işleme

Kenar bulma, filtreleme, nesne tanıma: her piksel ya da blok için aynı işlem (veri paralelliği, GPU).

Hesaplamalı akışkanlar dinamiği

Uçak, gemi, araç tasarımında akış simülasyonu: alan ızgaraya bölünür, her bölge bir işlemcide.

Genetik algoritmalar

Popülasyondaki bireylerin uygunluğu birbirinden bağımsız ve paralel değerlendirilir (çizelgeleme, rotalama).

Modeller ve Ölçütler

Flynn Sınıflandırması

SınıfAçılımAnlamıÖrnek
SISDSingle Instruction, Single Datatek komut akışı, tek veriklasik tek çekirdekli işlemci
SIMDSingle Instruction, Multiple Dataaynı komut, birçok veri üzerinde aynı andavektör komutları (AVX), GPU
MISDMultiple Instruction, Single Datafarklı komutlar aynı veri üzerindenadir; hata toleranslı sistemler
MIMDMultiple Instruction, Multiple Dataher işlemci kendi programını kendi verisindeçok çekirdekli CPU, kümeler
Veri paralelliği: aynı işlem verinin farklı parçalarına (SIMD tarzı).
Görev paralelliği: farklı görevler aynı anda (MIMD tarzı).

Modeller ve Ölçütler

Bellek Mimarileri

Paylaşımlı bellekortak bellekP₀P₁P₂P₃iş parçacıkları, kilitlerDağıtık bellekP₀BP₁BP₂BP₃Bağ (mesajlar)MPI, Hadoop, Spark
  • Paylaşımlı bellek (shared memory): tüm işlemciler aynı adres uzayını görür. İletişim ucuzdur; eşzamanlı erişim senkronizasyon ister.
  • Java iş parçacıkları, ForkJoinPool, OpenMP.
  • Dağıtık bellek (distributed memory): her düğümün kendi belleği vardır; veri mesajla taşınır.
  • Ölçeklenir ama iletişim pahalıdır: MPI, Hadoop MapReduce.

Modeller ve Ölçütler

PRAM Modeli

  • PRAM (Parallel Random Access Machine): paralel algoritmaların kuramsal modeli; sıralı RAM modelinin paralel karşılığı.
  • p işlemci, ortak bir bellek ve ortak saat: işlemciler adımları eş zamanlı (lockstep) atar.
  • Her adımda bir işlemci: bellekten oku → yerel hesapla → belleğe yaz. Her biri O(1) sürer.
  • İletişim ve senkronizasyon maliyeti yok sayılır; bu yüzden algoritmanın içsel paralelliğini ölçer.
TürOkumaYazma
EREWdışlayıcıdışlayıcı
CREWeşzamanlıdışlayıcı
CRCWeşzamanlıeşzamanlı
E = Exclusive (aynı hücreye bir adımda tek işlemci), C = Concurrent (birden çok işlemci). CRCW'de çakışan yazmalar bir kuralla çözülür (ortak değer, rastgele biri, öncelikli olan…).

Modeller ve Ölçütler

Hızlanma, Verim, Maliyet

ÖlçütTanım
T₁en iyi sıralı algoritmanın süresi
Tₚp işlemcideki paralel süre
Hızlanma (speedup)S = T₁ / Tₚ (ideal: S = p)
Verim (efficiency)E = S / p (0 < E ≤ 1)
Maliyet (cost)C = p · Tₚ
Örnek: T₁ = 100 s, p = 8, T₈ = 16 s
S = 100 / 16 = 6,25
E = 6,25 / 8 ≈ 0,78
C = 8 · 16 = 128 s (> 100 s)
  • Maliyet-optimal: C = Θ(T₁).
  • S < p olmasının nedenleri: iletişim, bekleme, yük dengesizliği, sıralı kısımlar.

Modeller ve Ölçütler

Amdahl Yasası

  • Programın f kesri paralelleştirilebilir, 1 − f kesri sıralıdır.
  • S(p) = 1 / ((1 − f) + f / p)
  • p → ∞ iken S → 1 / (1 − f): sıralı kısım hızlanmayı sınırlar.
  • f = 0,9, p = 8: S = 1 / (0,1 + 0,1125) ≈ 4,71; sınır 10.
Gustafson yasası: problem boyutu p ile büyürse S = (1 − f) + f · p. f = 0,9, p = 8 → S = 7,3. Büyük problemlerde paralellik daha karlıdır.
051015201416642561024işlemci sayısı p (log ölçek)hızlanma S(p)f = 0,95f = 0,9f = 0,75f = 0,5

Modeller ve Ölçütler

İş ve Derinlik

  • İş (work) W: tüm işlemlerin toplam sayısı = T₁ (tek işlemcide süre).
  • Derinlik (depth, span) D: en uzun bağımlılık zinciri = T∞ (sınırsız işlemcide süre).
  • Paralellik = W / D: yararlı kullanılabilecek en fazla işlemci sayısı.
  • Alt sınırlar: Tₚ ≥ W / p ve Tₚ ≥ D.
  • Brent teoremi: Tₚ ≤ W / p + D.
  • İş-verimli (work-efficient): W, en iyi sıralı algoritmayla aynı mertebede.
Örnek: n sayının ağaçla toplanması
W = n − 1 toplama, D = log₂ n tur.
n = 1024: W = 1023, D = 10, paralellik ≈ 102.
p = 32 için Brent: T₃₂ ≤ 1023/32 + 10 ≈ 42 adım.

PRAM ile Toplama

Problem: Paralel Toplama

  • Girdi: n sayı; çıktı: toplamları. Sıralı algoritma n − 1 toplama yapar: O(n).
  • Sıralı döngüde her toplama bir öncekini bekler: zincir uzunluğu n − 1, paralellik yok.
  • Toplama birleşmeli (associative) olduğu için parantezleri değiştirebiliriz:
    ((2 + 3) + (5 + 1)) + ((7 + 6) + (8 + 4)) → dengeli bir ikili ağaç.
  • Ağacın her düzeyindeki toplamlar birbirinden bağımsızdır → aynı turda paralel yapılır.
  • Aynı fikir her birleşmeli işlem için çalışır: max, min, çarpım, AND, OR (indirgeme, reduction).
Örnek dizi: 2, 3, 5, 1, 7, 6, 8, 4 → toplam 36. 8 işlemci p₀ … p₇ birer sayı tutar.

PRAM ile Toplama · Adım adım

PRAM Toplama Adım Adım

p0p1p2p3p4p5p6p723517684tur 1tur 2tur 3

Başlangıç: 8 sayı 8 işlemciye (p₀ … p₇) birer birer dağıtılır. Kesikli kutular, sonraki turlarda yazılacak hücrelerdir.

p0p1p2p3p4p5p6p723517684561312tur 1tur 2tur 3

Tur 1: 4 işlemci aynı anda komşu çiftleri toplar: 2+3=5, 5+1=6, 7+6=13, 8+4=12.

p0p1p2p3p4p5p6p7235176845613121125tur 1tur 2tur 3

Tur 2: 2 işlemci, aradaki uzaklık 2 olan kısmi toplamları birleştirir: 5+6=11, 13+12=25.

p0p1p2p3p4p5p6p723517684561312112536tur 1tur 2tur 3

Tur 3: p₀, 11+25 = 36 sonucunu bulur. 8 sayı log₂ 8 = 3 turda toplandı (sıralı: 7 adım).

PRAM ile Toplama · Kodu adım adım çalıştır

Ağaç Toplamı: Kodu Adım Adım İzle

2031521374658647

Dizi oluşturulur; n = 8. Her hücreyi bir işlemcinin tuttuğunu düşünün.

2031521374658647

Yeni tur: adim = 1. Bu turda 4 toplama paralel yapılır.

5031521374658647

a[0] = a[0] + a[1] = 2 + 3 = 5.

5031621374658647

a[2] = a[2] + a[3] = 5 + 1 = 6.

50316213134658647

a[4] = a[4] + a[5] = 7 + 6 = 13.

503162131346512647

a[6] = a[6] + a[7] = 8 + 4 = 12.

503162131346512647

Yeni tur: adim = 2. Bu turda 2 toplama paralel yapılır.

1103162131346512647

a[0] = a[0] + a[2] = 5 + 6 = 11.

1103162132546512647

a[4] = a[4] + a[6] = 13 + 12 = 25.

1103162132546512647

Yeni tur: adim = 4. Bu turda 1 toplama paralel yapılır.

3603162132546512647

a[0] = a[0] + a[4] = 11 + 25 = 36.

3603162132546512647

adim = 8 → döngü biter. Toplam a[0] = 36; 3 tur, 7 toplama.

int[] a = {2, 3, 5, 1, 7, 6, 8, 4};
int n = a.length;
for (int adim = 1; adim < n; adim *= 2) {
  // aynı turdaki tüm i'ler paralel
  for (int i = 0; i + adim < n; i += 2 * adim)
    a[i] = a[i] + a[i + adim];
}  // tur sonu: senkronizasyon
// toplam a[0]'da

PRAM ile Toplama

PRAM Toplama: Analiz

Ölçütn işlemci (n/2 yeterli)p = n / log₂ n işlemci
Süre Tₚlog₂ nO(log n)
İş Wn − 1n − 1
Maliyet p · TₚΘ(n log n)Θ(n)
Maliyet-optimal mi?hayırevet
  • Turlar ilerledikçe çalışan işlemci sayısı yarıya iner (4, 2, 1): çoğu işlemci boşta bekler, maliyet yüksektir.
  • Çözüm: her işlemci önce kendi log₂ n'lik bloğunu sıralı toplar (O(log n)), sonra n / log₂ n kısmi toplam ağaçla birleştirilir (O(log n)).
  • EREW yeterlidir: bir turda her hücreyi tek işlemci okur/yazar. Her tur sonunda bir senkronizasyon (bariyer) gerekir.

PRAM ile Toplama

Paralel Önek Toplamı

  • Önek toplamı (prefix sum, scan): yᵢ = x₀ + x₁ + … + xᵢ.
  • Sıralı: yᵢ = yᵢ₋₁ + xᵢ, O(n) ama tamamen zincirleme.
  • Hillis–Steele: d = 1, 2, 4, … için her i ≥ d paralel olarak x[i] += x[i − d].
  • D = ⌈log₂ n⌉ tur, W = O(n log n) → iş-verimli değil.
  • Blelloch algoritması (yukarı/aşağı süpürme) W = O(n), D = O(log n).
  • Kullanım: paralel sıralama, sıkıştırma (filter), Java'da Arrays.parallelPrefix.
Toplamadaki ağaç yalnızca son hücreyi (toplamı) verir; önek toplamında her hücre kendi önekini öğrenmelidir.

PRAM ile Toplama · Adım adım

Hillis–Steele Önek Toplamı Adım Adım

başlangıç23517684

Girdi: 2 3 5 1 7 6 8 4. Amaç: her i için x₀ + … + xᵢ (kapsayıcı önek toplamı).

başlangıç23517684d = 125868131412

d = 1: i ≥ 1 olan her işlemci kendi değerine solundakini ekler (7 toplama, aynı anda).

başlangıç23517684d = 125868131412d = 225101116192225

d = 2: i ≥ 2 için 2 soldakini ekler. Artık her hücre 4 elemanlık pencerenin toplamıdır.

başlangıç23517684d = 125868131412d = 225101116192225d = 425101118243236

d = 4: sonuç 2 5 10 11 18 24 32 36. log₂ 8 = 3 turda bitti; ama toplam 7+6+4 = 17 toplama yapıldı.

Boru Hattı

Boru Hattı Fikri

  • Boru hattı (pipeline): iş, ardışık aşamalara bölünür; her aşama bir işlemcidir.
  • Fabrika montaj hattı gibi: bir iş 2. aşamaya geçerken 1. aşama bir sonraki işe başlar.
  • Tek bir işin süresi kısalmaz; ama birim zamanda biten iş (throughput) artar.
  • k aşama, m iş: sıralı k · m adım; boru hattıyla k + m − 1 adım.
  • Başta hat dolarken ve sonda boşalırken bazı aşamalar boştur.
t₁t₂t₃t₄t₅t₆aşama 1iş 1iş 2iş 3iş 4aşama 2iş 1iş 2iş 3iş 4aşama 3iş 1iş 2iş 3iş 4

3 aşama, 4 iş: 3 · 4 = 12 yerine 3 + 4 − 1 = 6 adım.

Boru Hattı

Boru Hattı Problemi

  • 5 işlemci p₀ … p₄ doğrusal bir zincir oluşturur; her işlemci yalnızca sağ komşusuna mesaj gönderebilir.
  • Her pj, 4 değerlik bir sütun tutar (satır 0 … 3).
  • Amaç: her satır r için pj'deki değer, p₀ … pj'nin o satırdaki değerlerinin toplamı olsun (satır bazında önek toplamı). Böylece p₄ her satırın toplamını tutar.
  • Bir adımda her işlemci bir değer gönderir; alıcı onu kendi değerine ekler.
  • Saf yöntem: satır 0'ı zincir boyunca taşı (4 adım), sonra satır 1'i… → 4 · 4 = 16 adım.
  • Boru hattı: pj, satır r'yi t = r + j anında gönderir; satırlar zincirde arka arkaya akar.

Boru Hattı · Adım adım

Boru Hattı Adım Adım: 5 İşlemci, 4 Satır

p02174p13729p23473p36102p48635

Her pj 4 satırlık bir sütun tutar. Hedef: her satırda pj, p₀ … pj değerlerinin toplamını tutsun. p₀'ın değerleri zaten sonuçtur.

p02174p15729p23473p36102p48635+

Adım 1: p₀→p₁ satır 0: 2+3=5.

p02174p15829p28473p36102p48635++

Adım 2: p₀→p₁ satır 1: 1+7=8, p₁→p₂ satır 0: 5+3=8.

p02174p15899p281273p314102p48635+++

Adım 3: p₀→p₁ satır 2: 7+2=9, p₁→p₂ satır 1: 8+4=12, p₂→p₃ satır 0: 8+6=14.

p02174p158913p2812163p3141302p422635++++

Adım 4: p₀→p₁ satır 3: 4+9=13, p₁→p₂ satır 2: 9+7=16, p₂→p₃ satır 1: 12+1=13, p₃→p₄ satır 0: 14+8=22.

p02174p158913p28121616p31413162p4221935+++

Adım 5: p₁→p₂ satır 3: 13+3=16, p₂→p₃ satır 2: 16+0=16, p₃→p₄ satır 1: 13+6=19.

p02174p158913p28121616p314131618p42219195++

Adım 6: p₂→p₃ satır 3: 16+2=18, p₃→p₄ satır 2: 16+3=19.

p02174p158913p28121616p314131618p422191923+

Adım 7: p₃→p₄ satır 3: 18+5=23. Bitti: 7 adım; p₄ satır toplamlarını (22 19 19 23) tutar.

Boru Hattı

Boru Hattı: Analiz

adımp₀→p₁p₁→p₂p₂→p₃p₃→p₄
1satır 0———
2satır 1satır 0——
3satır 2satır 1satır 0—
4satır 3satır 2satır 1satır 0
5—satır 3satır 2satır 1
6——satır 3satır 2
7———satır 3
for (int t = 0; t < m + p - 2; t++)
  // tüm j'ler aynı anda
  for (int j = 0; j < p - 1; j++) {
    int r = t - j;
    if (r >= 0 && r < m)
      x[j + 1][r] += x[j][r];
  }
  • Adım sayısı: m + p − 2 = 4 + 5 − 2 = 7 (saf: m(p − 1) = 16).
  • Verim: m(p − 1) toplama / ((p − 1)(m + p − 2)) = m / (m + p − 2) = 4/7 ≈ %57.
  • m ≫ p iken verim → 1.

Boru Hatlı Ağaç

Ağaçta İndirgeme

  • İşlemciler bir ağaç biçiminde bağlıdır; her düğüm değerini ebeveynine gönderir, ebeveyn kendi değerine ekler. Sonuç kökte toplanır.
  • Ağacın derinliği h ise tek bir değerin indirgenmesi h tur sürer (örneğimizde h = 3).
  • Şimdi her işlemcide tek sayı değil, k bileşenli bir vektör var (örnekte k = 3: yeşil, mavi, kırmızı). Her bileşen ayrı ayrı toplanacak.
  • Saf yöntem: bileşenleri sırayla indirge → k · h = 9 tur.
  • Boru hatlı ağaç (pipelined tree): bir bileşen yukarı çıkarken bir sonraki bileşen yapraklardan yola çıkar.
  • Kural: bir düğüm bir turda en fazla bir mesaj alabilir (aynı anda bir mesaj da gönderebilir).

Boru Hatlı Ağaç · Adım adım

Boru Hatlı Ağaç Adım Adım

361p0375p1853p2958p3752p4345p5217p6

7 işlemcinin her biri 3 değerlik bir vektör tutar (yeşil, mavi, kırmızı). Hedef: üç bileşenin toplamı kökte (p₀) toplansın. Değerler alttan köke doğru akar.

361p01075p11753p2958p3752p4545p5217p6

Tur 1: yeşil p₃→p₂: 9+8=17, p₄→p₁: 7+3=10, p₆→p₅: 2+3=5.

861p02775p11753p2958p3752p4545p5217p6

Tur 2: yeşil p₂→p₁: 17+10=27, p₅→p₀: 5+3=8.

3561p027125p117103p2958p3752p4555p5217p6

Tur 3: yeşil p₁→p₀: 27+8=35; mavi p₃→p₂: 5+5=10, p₄→p₁: 5+7=12, p₆→p₅: 1+4=5.

35111p027225p117103p2958p3752p4555p5217p6

Tur 4: mavi p₂→p₁: 10+12=22, p₅→p₀: 5+6=11.

35331p027227p1171011p2958p3752p45512p5217p6

Tur 5: mavi p₁→p₀: 22+11=33; kırmızı p₃→p₂: 8+3=11, p₄→p₁: 2+5=7, p₆→p₅: 7+5=12.

353313p0272218p1171011p2958p3752p45512p5217p6

Tur 6: kırmızı p₂→p₁: 11+7=18, p₅→p₀: 12+1=13.

353331p0272218p1171011p2958p3752p45512p5217p6

Tur 7: kırmızı p₁→p₀: 18+13=31. Kökte (35, 33, 31): 7 turda bitti.

  • Kenarın rengi, o turda taşınan bileşeni gösterir; ok ebeveyne doğrudur.
  • Kalın çerçeveli kutu, bu turda güncellenen değerdir.
  • Her bileşen 3 aşamada köke çıkar:
    (1) p₃→p₂, p₄→p₁, p₆→p₅
    (2) p₂→p₁, p₅→p₀
    (3) p₁→p₀.
  • Yeni bileşen 2 turda bir başlar.

Boru Hatlı Ağaç

Boru Hatlı Ağaç: Analiz

turaşama 1
p₃→p₂, p₄→p₁, p₆→p₅
aşama 2
p₂→p₁, p₅→p₀
aşama 3
p₁→p₀
1yeşil——
2—yeşil—
3mavi—yeşil
4—mavi—
5kırmızı—mavi
6—kırmızı—
7——kırmızı
  • Neden 2 turda bir? p₁ iki çocuğundan (p₄ ve p₂) mesaj alır; bir turda tek mesaj alabildiği için bir bileşen p₁'i 2 tur meşgul eder. p₀ için de aynısı.
  • Toplam tur: h + (k − 1) · 2 = 3 + 2 · 2 = 7 (saf: k · h = 9).
  • k büyüdükçe: 2k + 1 ≈ 2k tur; saf yöntem 3k. Genel olarak tur ≈ h + (k − 1) · (en fazla çocuk sayısı).
  • Sonuç kökte: yeşil 35, mavi 33, kırmızı 31.

Paralel Algoritma Türleri

Paralel Algoritma Türleri

Böl ve fethet

Problem bağımsız alt problemlere bölünür; alt problemler farklı çekirdeklerde aynı anda çözülür, sonuçlar birleştirilir. Paralel birleştirme sıralaması, hızlı sıralama, matris çarpımı.

MapReduce

Büyük veri dağıtık düğümlerde işlenir: map adımı ara anahtar–değer çiftleri üretir, reduce adımı bunları birleştirir. Hadoop, Spark; sayma, dizinleme, günlük analizi.

Veri paralel

Aynı hesaplama verinin farklı parçalarına aynı anda uygulanır (SIMD komutları, GPU). Bilimsel simülasyon, görüntü işleme, sayısal hesaplama.

görevalt görev 1alt görev 2alt görev 3birleştirfork()join()

Paralel Algoritma Türleri

Paralel Birleştirme Sıralaması

class SiralamaGorevi extends RecursiveTask<int[]> {
  private final int[] dizi;
  SiralamaGorevi(int[] dizi) { this.dizi = dizi; }

  protected int[] compute() {
    if (dizi.length <= 1) return dizi;
    int orta = dizi.length / 2;
    var sol = new SiralamaGorevi(
        Arrays.copyOfRange(dizi, 0, orta));
    var sag = new SiralamaGorevi(
        Arrays.copyOfRange(dizi, orta, dizi.length));
    sol.fork();               // paralel başlat
    sag.fork();
    return birlestir(sol.join(), sag.join());
  }
}
// kullanım:
int[] s = new ForkJoinPool().invoke(
    new SiralamaGorevi(dizi));
  • RecursiveTask: sonuç döndüren Fork/Join görevi.
  • fork(): alt görevi havuza verir (asenkron).
  • join(): alt görevin bitmesini bekler, sonucunu alır.
  • birlestir: bilinen sıralı birleştirme, O(n).
  • ForkJoinPool iş çalma (work stealing) ile boşta kalan çekirdeğe iş verir.

Paralel Algoritma Türleri · Adım adım

Paralel Birleştirme Sıralaması: 2 3 5 1 7 6 8 4

dizi23517684

Görev: 8 elemanlı diziyi sırala. SiralamaGorevi kök görevdir.

dizi23517684fork (böl)23517684

Görev diziyi ikiye böler ve iki alt görevi fork() ile havuza verir; iki yarı aynı anda işlenebilir.

dizi23517684fork (böl)23517684fork (böl)23517684

Her alt görev de böler: artık 4 görev paralel çalışabilir.

dizi23517684fork (böl)23517684fork (böl)23517684fork (böl)23517684

Taban durumu: 1 elemanlı diziler zaten sıralıdır (8 yaprak görev).

dizi23517684fork (böl)23517684fork (böl)23517684fork (böl)23517684join (birleştir)23156748

join(): her ebeveyn iki çocuğunun sonucunu bekler ve birleştirir: [2 3] [1 5] [6 7] [4 8].

dizi23517684fork (böl)23517684fork (böl)23517684fork (böl)23517684join (birleştir)23156748join (birleştir)12354678

Bir üst düzeyde iki birleştirme paralel yapılır: [1 2 3 5] ve [4 6 7 8].

dizi23517684fork (böl)23517684fork (böl)23517684fork (böl)23517684join (birleştir)23156748join (birleştir)12354678join (birleştir)12345678

Kök görev son birleştirmeyi tek başına yapar: [1 2 3 4 5 6 7 8]. Bu sıralı birleştirme, derinliği (span) Θ(n) yapar.

Paralel Algoritma Türleri

Paralel Sıralama: Analiz

Sürümİş WDerinlik DParalellik W / D
Sıralı birleştirme sıralamasıΘ(n log n)Θ(n log n)1
Paralel özyineleme + sıralı birleştirmeΘ(n log n)Θ(n)Θ(log n)
Paralel özyineleme + paralel birleştirme (CLRS)Θ(n log n)Θ(log³ n)Θ(n / log² n)
  • Derinlik yinelemesi: D(n) = D(n/2) + Θ(n) = Θ(n), çünkü iki yarı paralel ama birleştirme sıralıdır.
  • Paralellik yalnızca Θ(log n): n = 10⁶ için ≈ 20 çekirdekten fazlası pek fayda etmez.
  • Uygulamada: küçük parçalarda (örn. < 1000 eleman) sıralı sıralamaya geçin; aksi hâlde görev oluşturma yükü kazancı yer.
  • Hazır çözüm: Arrays.parallelSort(dizi).

Paralel Algoritma Türleri

MapReduce

  • Map: her parça bağımsız işlenir ve ara anahtar–değer çiftleri üretir (kelime → adet).
  • Karıştır (shuffle): aynı anahtarlar aynı reducer'a toplanır.
  • Reduce: her anahtarın değerleri birleştirilir (toplanır).
  • Örnekte: 13 kelime, 4 iş parçacığı → parça boyu ⌊13/4⌋ = 3; son parça 4 kelime.
Bölme (split)Map görevleriReduceapple, bananaappleapple:2, banana:1orange, bananaappleorange:1, banana:1apple:1banana, bananaorangebanana:2, orange:1apple, cherrybanana, appleapple:2, cherry:1banana:1apple: 5banana: 5orange: 2cherry: 1

Paralel Algoritma Türleri

MapReduce: Kod

// Map: bir parçadaki kelimeleri say
protected Map<String, Integer> compute() {
  Map<String, Integer> sonuc = new HashMap<>();
  for (String kelime : parca)
    sonuc.merge(kelime, 1, Integer::sum);
  return sonuc;
}
// Ana akış
for (MapGorevi g : mapGorevleri) g.fork();
List<Map<String, Integer>> ara = new ArrayList<>();
for (MapGorevi g : mapGorevleri) ara.add(g.join());
// Reduce: ara sonuçları birleştir
Map<String, Integer> toplam = new HashMap<>();
for (Map<String, Integer> m : ara)
  m.forEach((k, v) -> toplam.merge(k, v, Integer::sum));
  • Her map görevinin kendi HashMap'i vardır: paylaşılan durum yok, kilit gerekmez.
  • Sonuç: apple 5, banana 5, orange 2, cherry 1.
  • Bu örnekte reduce tek görevdir; gerçek MapReduce'ta anahtarlar birçok reducer'a bölüştürülür (hash(k) mod r).

Paralel Algoritma Türleri

Veri Paralelliği: Matris Çarpımı

// her satır ayrı bir görev
class SatirGorevi extends RecursiveAction {
  protected void compute() {
    for (int j = 0; j < n; j++) {
      C[satir][j] = 0;
      for (int k = 0; k < n; k++)
        C[satir][j] += A[satir][k] * B[k][j];
    }
  }
}
try (var havuz = new ForkJoinPool()) {
  for (int i = 0; i < n; i++)
    havuz.submit(new SatirGorevi(i));
}   // close(): tüm görevleri bekler
C = A · B
302418
846954
13811490
  • A = [[1,2,3],[4,5,6],[7,8,9]], B = [[9,8,7],[6,5,4],[3,2,1]].
  • Satırlar bağımsız: n görev, her biri Θ(n²) iş. W = Θ(n³), D = Θ(n²) (satır başına).
  • Her görev yalnızca kendi satırına yazar → yarış yok.

Paralel Algoritma Türleri

Yarış Durumu

İki iş parçacığı paylaşılan sayac'ı aynı anda artırır. sayac++ aslında üç adımdır: oku → artır → yaz.

zamanİş parçacığı 1İş parçacığı 2sayac
1oku (0)0
2oku (0)0
3yaz 0 + 11
4yaz 0 + 11

Beklenen 2, sonuç 1: kayıp güncelleme (lost update).

  • Yarış durumu (race condition): sonuç, iş parçacıklarının zamanlamasına bağlıdır; hata her çalıştırmada ortaya çıkmayabilir.
  • Çözümler: synchronized blok / kilit, AtomicInteger.incrementAndGet(), eşzamanlı koleksiyonlar (ConcurrentHashMap).
  • En iyisi: paylaşılan durumdan kaçının. Her görev kendi kısmi sonucunu üretsin, sonra birleştirin (indirgeme, MapReduce).
  • Kilitler de bedelsiz değildir: sıralı bölge oluşturur (Amdahl) ve kilitlenme (deadlock) riski getirir.

Paralel Algoritma Türleri

Eşzamanlı Çizge Gezinme

12345678
  • Fikir: her ziyaret edilmemiş komşu için yeni bir gezinme görevi fork() edilir; alt ağaçlar paralel gezilir.
  • Görevler ziyaret kümesini paylaşır. Bu küme sıradan bir HashSet olursa eşzamanlı erişimde güvenli değildir.
  • Ayrıca contains + add iki ayrı adımdır: iki görev aynı düğümü birlikte ziyaret edebilir.
Set<Dugum> ziyaret = ConcurrentHashMap.newKeySet();
if (!ziyaret.add(komsu)) continue; // atomik kontrol+ekle

Düzey eşzamanlı BFS: her düzeyin tüm düğümleri paralel genişletilir, düzey sonunda bariyer; D = O(çap).

Paralel Algoritma Türleri

Java'da Paralellik Araçları

AraçNe zaman?
Thread, Runnableen alt düzey; elle yönetim, nadiren doğrudan kullanılır
ExecutorServicebağımsız görevleri sabit bir iş parçacığı havuzunda çalıştırmak
ForkJoinPool, RecursiveTaskböl ve fethet; iş çalma ile özyinelemeli görevler
list.parallelStream()veri paralel map / filter / reduce (ortak ForkJoinPool kullanır)
Arrays.parallelSortbüyük dizileri paralel sıralamak
Arrays.parallelPrefixparalel önek toplamı (scan)
AtomicInteger, ConcurrentHashMappaylaşılan sayaç/küme gerektiğinde güvenli erişim
Map<String, Long> adet = kelimeler.parallelStream()
    .collect(Collectors.groupingByConcurrent(k -> k, Collectors.counting()));

Özet

Özet

KonuHatırlanacaklar
Fikirböl → işlemcilere ata → aynı anda çöz → birleştir; bedeli iletişim, senkronizasyon, yük dengeleme
ModellerFlynn: SISD/SIMD/MISD/MIMD; PRAM: EREW, CREW, CRCW; paylaşımlı / dağıtık bellek
ÖlçütlerS = T₁/Tₚ, E = S/p, C = p·Tₚ; Amdahl S ≤ 1/(1 − f); Brent Tₚ ≤ W/p + D
PRAM toplamalog₂ n tur, W = n − 1; p = n/log n ile maliyet-optimal
Önek toplamıHillis–Steele: log₂ n tur, O(n log n) iş; Blelloch: O(n) iş
Boru hattıp işlemci, m satır: m + p − 2 adım (saf m(p − 1))
Boru hatlı ağaçh + (k − 1)·2 tur (örnek 7; saf k·h = 9)
JavaFork/Join (fork, join), MapReduce, satır başına görev; paylaşılan durumda yarış → atomik/eşzamanlı yapılar

Özet

Sık Yapılan Hatalar

p işlemci = p kat hız sanmakSıralı kısım (Amdahl), iletişim ve bekleme yüzünden S < p'dir. %10 sıralı kod hızlanmayı 10 ile sınırlar.
Paylaşılan HashSet / sayaçEşzamanlı yazma yarış durumuna yol açar. ConcurrentHashMap, AtomicInteger ya da yerel sonuç + birleştirme kullanın.
Çok ince taneli görevlerHer eleman için fork() yapmak, görev oluşturma yükünü artırır. Bir eşiğin altında sıralı çalışın.
Turlar arası senkronizasyonu unutmakPRAM toplamada tur t + 1, tur t'nin tüm yazmaları bitmeden başlarsa eski değerler okunur.
Yalnızca derinliğe bakmakHillis–Steele O(log n) turda biter ama O(n log n) iş yapar; az işlemcide sıralı taramadan yavaş olabilir.
Boru hattı adımını yanlış saymakHattın dolma süresi unutulur: m satır, p işlemci için m adım değil, m + p − 2 adım.

Özet

Örnek Problemler

  1. n = 16 sayı PRAM ağacıyla toplanıyor. Kaç tur sürer, ilk turda kaç işlemci çalışır, toplam kaç toplama yapılır?
  2. Boru hattında p = 5 işlemci ve m = 100 satır varsa kaç adım gerekir? Saf yöntemle karşılaştırın.
  3. Bölümdeki boru hatlı ağaç örneğinde (7 işlemci, h = 3) her işlemci k = 10 bileşenli vektör tutsaydı kaç tur gerekirdi?
  4. Programın %80'i paraleldir. p = 4 için Amdahl hızlanması nedir, üst sınır kaçtır?
  5. T₁ = 120 s, T₆ = 30 s. Hızlanma, verim ve maliyeti bulun.
  6. [1, 2, 3, 4] dizisinin Hillis–Steele önek toplamını turlar hâlinde yazın; kaç toplama yapılır?
Cevapları göster
  1. log₂ 16 = 4 tur; ilk turda 8 işlemci; 8 + 4 + 2 + 1 = 15 toplama (= n − 1).
  2. m + p − 2 = 103 adım; saf m(p − 1) = 400 adım (≈ 3,9 kat).
  3. 3 + (10 − 1) · 2 = 21 tur (saf 10 · 3 = 30).
  4. S = 1 / (0,2 + 0,8/4) = 1 / 0,4 = 2,5; sınır 1 / 0,2 = 5.
  5. S = 4, E = 4/6 ≈ 0,67, C = 6 · 30 = 180 s.
  6. d = 1: [1, 3, 5, 7]; d = 2: [1, 3, 6, 10]. 3 + 2 = 5 toplama (sıralı: 3).

Özet

Alıştırmalar

  1. PRAM ağaç toplamını en büyük eleman bulacak şekilde değiştirin. Süre ve iş nedir?
  2. n = 8 için Hillis–Steele önek toplamı kaç toplama yapar? Sıralı algoritmayla karşılaştırın.
  3. Paralel gezinmedeki ziyaret kümesini iş parçacığı güvenli yapın.
  4. Paralel birleştirme sıralamasına eşik ekleyin; neden iki alt görevden birini fork() yerine doğrudan compute() etmek daha iyidir?
  5. p = 32 işlemcide S = 16 hızlanma için programın en az ne kadarı paralel olmalıdır (Amdahl)?
  6. m satır, p işlemcili boru hattında adım sayısını ve verimi genel olarak ifade edin.
Cevaplar / ipuçları
  1. a[i] = Math.max(a[i], a[i + adim]); D = log₂ n, W = n − 1.
  2. d = 1: 7, d = 2: 6, d = 4: 4 → 17 toplama; sıralı 7. Genel: n log₂ n − (n − 1).
  3. ConcurrentHashMap.newKeySet() kullanın ve ziyaret.add(komsu) ile kontrol + ekleme atomik olsun.
  4. Boyut < eşik ise Arrays.sort. sol.fork(); x = sag.compute(); y = sol.join();: iş parçacığı boşta beklemez, görev sayısı yarıya iner.
  5. 1 / ((1 − f) + f/32) = 16 → 1 − (31/32) f = 1/16 → f = 30/31 ≈ %96,8.
  6. Adım: m + p − 2; verim: m / (m + p − 2).

Özet

Kaynaklar

  • Cormen, Leiserson, Rivest ve Stein, Introduction to Algorithms, 4. baskı, MIT Press, 2022 (Bölüm 26: Parallel Algorithms).
  • J. JáJá, An Introduction to Parallel Algorithms, Addison-Wesley, 1992.
  • A. Grama, A. Gupta, G. Karypis ve V. Kumar, Introduction to Parallel Computing, 2. baskı, Addison-Wesley, 2003.
  • G. M. Amdahl, "Validity of the Single Processor Approach to Achieving Large Scale Computing Capabilities", AFIPS, 1967.
  • J. Dean ve S. Ghemawat, "MapReduce: Simplified Data Processing on Large Clusters", OSDI, 2004.
  • D. Lea, "A Java Fork/Join Framework", ACM Java Grande Conference, 2000.

Son

Bölüm 10: Paralel Algoritmalar
Önceki bölüm: Bölüm 9: Çevrimiçi Algoritmalar · Sonraki bölüm: Bölüm 11: Böl ve Fethet Yaklaşımı
1 / 1 Sercan KÜLCÜ, Tüm hakları saklıdır.