Concurrency (eşzamanlılık), bir işlemcinin aynı zaman dilimi içinde birden fazla görevin ilerlemesini yönetme yeteneğini ifade eder. Burada kritik nokta, görevlerin gerçekten aynı anda yürütülmesi değil, işlemci zamanının bölünerek farklı görevler arasında hızla geçiş yapılması ve böylece ilerleme sağlanmasıdır. Bu, tek çekirdekli sistemlerde dahi uygulanabilen soyut bir tasarım modelidir.

Parallelism (paralellik) ise, birden fazla işlemcinin veya çekirdeğin, gerçekten aynı fiziksel anda farklı görevleri veya bir görevin farklı parçalarını yürütmesidir. Paralellik, donanım kaynaklarının çoğaltılmasına dayanır ve temel amacı, bir iş yükünün toplam yürütme süresini azaltmaktır. Bu iki kavram birbirini dışlayan değil, tamamlayan kavramlardır.

Aralarındaki temel felsefi ayrım, concurrency'nin yapılandırma (structure) ile, parallelism'in ise yürütme (execution) ile ilgili olmasıdır. Concurrency, bir programın birden fazla bağımsız veya zayıf bağlı iş parçacığına (thread) nasıl bölünebileceğini tasarlamakla ilgilidir. Parallelism ise, bu tasarlanmış iş parçacıklarının fiziksel olarak paralel işlemcilerde aynı anda çalıştırılmasıdır.

Kullanılan temel bileşenler de bu ayrımı yansıtır. Concurrency modellerinde iş parçacıkları (threads), olay döngüleri (event loops) ve korutinler (coroutines) öne çıkarken, parallelism uygulamalarında genellikle işlemci çekirdeklerine (cores) ve vektör birimlerine (SIMD) doğrudan atıfta bulunulur. Concurrency, yarış koşulları (race conditions) ve kilitlenmeler (deadlocks) gibi mantıksal sorunlara odaklanrken; parallelism, veri bölümleme (data partitioning) ve iş yükü dengeleme (load balancing) gibi performans odaklı sorunları ele alır.

  • Concurrency: Zaman paylaşımı üzerinden çoklu görev ilerlemesi (yönetim).
  • Parallelism: Kaynak çoğaltma üzerinden aynı anda çoklu görev yürütülmesi (performans).
  • İlişki: Bir sistem paralel olmadan eşzamanlı olabilir, ancak etkili paralellik genellikle iyi bir eşzamanlı tasarım gerektirir.

Temel Analoji: Kahve Dükkanı

Bu iki kavramın farkını somutlaştırmak için, tek bir çalışanı (barista) ve çoklu sipariş alan bir kahve dükkanı senaryosu ele alınabilir. Çalışan, tek bir espresso makinesine sahiptir. Concurrency durumunda, çalışan aynı anda üç müşterinin siparişini alır: bir espresso, bir filtre kahve ve bir çay.

Çalışan, espresso makinesini çalıştırır ve hazırlanırken beklemek yerine, filtre kahvenin filtresini hazırlar ve suyu koyar. Espresso fincanı dolarken, çay için suyu ısıtmaya başlar ve bardağı hazırlar. Burada çalışan zamanlama yönetimi yaparak, tek bir kaynakla üç görevi de ilerletmektedir. Hiçbir iki işlem aynı fiziksel anda makineyi kullanmaz, ancak tüm siparişler eşzamanlı olarak ilerler.

Parallelism senaryosunda ise, dükkanda üç çalışan ve üç espresso makinesi olduğunu hayal edin. Her çalışan, bir siparişin tamamından sorumlu olabilir ve üç sipariş de tamamen aynı anda, birbirini beklemeye gerek kalmadan hazırlanır. Bu, kaynakların (işgücü ve makine) çoğaltılmasıyla sağlanan gerçek bir paralel yürütmedir. Concurrency, kaynak kısıtı altında verimlilik artırırken; parallelism, kaynak artırımıyla iş çıktısını doğrusala yakın ölçeklendirir.

İşlemsel Modeller ve Mimari

Concurrency ve parallelism, farklı programlama modelleri ve donanım mimarileri ile uygulanır. Concurrency için en yaygın model, paylaşılan bellekli çoklu iş parçacığı (multithreading) modelidir. Bu modelde, bir süreç içindeki iş parçacıkları aynı bellek alanını paylaşarak iletişim kurar, ancak bu durum bellek tutarlılığı (memory consistency) ve senkronizasyon gereksinimlerini beraberinde getirir. Alternatif bir model ise, mesaj geçişli (message-passing) mimarilerdir; burada işlemler veya "aktorler" (actors) izole bellek alanlarına sahiptir ve yalnızca mesaj alışverişiyle iletişim kurar, bu da birçok eşzamanlılık hatasını önler.

Parallelism ise, donanım düzeyinde farklı formlarda ortaya çıkar. SIMD (Single Instruction, Multiple Data) mimarisi, aynı komutun birden fazla veri öğesi üzerinde paralel olarak yürütülmesini sağlar ve grafik işleme (GPU) ile bilimsel hesaplamalarda kritiktir. MIMD (Multiple Instruction, Multiple Data) mimarisi ise çok çekirdekli (multi-core) ve çok işlemcili (multi-processor) sistemlerin temelidir; her çekirdek bağımsız komut dizilerini farklı veriler üzerinde çalıştırabilir. Paralel programlama modelleri, bu mimarileri verimli kullanmak için OpenMP, MPI (Message Passing Interface) veya CUDA gibi API'lar ve çatılar sunar.

Kriter Concurrency (Eşzamanlılık) Parallelism (Paralellik)
Temel Amaç Kaynak kullanım verimliliği, yanıt verebilirlik (responsiveness), modüler tasarım. İş yükü yürütme süresinde azalma (hızlanma - speedup), verimlilik (throughput) artışı.
Temel Zorluk Yarış koşulları (race conditions), kilitlenmeler (deadlocks), ortak kaynak yönetimi. İş yükü dengeleme (load balancing), veri bağımlılıkları (data dependencies), ölçeklenebilirlik (scalability).
Donanım Gereksinimi Zorunlu değildir; tek çekirdekte zaman paylaşımı ile sağlanabilir. Çoklu çekirdek, işlemci veya hesaplama birimi gerektirir.
Programlama Odağı Görev yapısı ve senkronizasyon (mutex, semafor). Veri/hesaplama bölümleme ve dağıtımı.

İki kavramın kesişimi, paralel donanım üzerinde çalışan eşzamanlı yazılımlarda ortaya çıkar. Örneğin, bir web sunucusu, her bir gelen isteği eşzamanlı olarak işlemek üzere bir iş parçacığı havuzu (thread pool) kullanır (concurrency). Eğer bu sunucu çok çekirdekli bir makinede çalışıyorsa, işletim sistemi bu iş parçacıklarını farklı çekirdeklere atayarak paralel yürütmeyi sağlar. Bu nedenle, modern yüksek performanslı sistemler, iyi tasarlanmış eşzamanlılığı, paralel donanım üzerinde çalıştırarak nihai performnsa ulaşır. Soyut eşzamanlı modeller olmadan, paralel donanımın potansiyeli tam olarak kullanılamaz; veri yarışları ve tutarsızlıklar performansı düşürebilir veya yanlış sonuçlara yol açabilir.

Tasarım ve Uygulama Yaklaşımları

Concurrency odaklı tasarımda, paylaşılan hiçbir şey olmaması (shared-nothing) veya değişmez veri yapıları (immutable data structures) gibi ilkeler önem kazanır. Bu ilkeler, senkronizasyon ihtiyacını en aza indirgeyerek eşzamanlılık hatalarının önüne geçer. Fonksiyonel programlama dilleri, değişmezlik ve yan etkisiz fonksiyonlar (pure functions) vurgularıyla doğal olarak bu modele uygundur. Asenkron programlama modelleri, olay döngüleri ve `async/await` anahtar kelimeleri ile bloke olmayan (non-blocking) g/ç işlemleri üzerinden eşzamanlılığı yöneterek yüksek ölçeklenebilirlik sağlar.

Parallelism odaklı tasarım ise genellikle "böl ve yönet (divide and conquer)" algoritmalarına, örneğin MapReduce veya paralel sıralama (parallel sort) algoritmalarına dayanır. Burada problem, birbirinden mümkün olduğunca bağımsız alt görevlere bölünür, bu alt görevler paralel olarak işlenir ve sonuçlar birleştirilir. Veri paralelliği (data parallelism), aynı işlemin büyük bir veri kümesinin farklı bölümleri üzerinde paralel çalıştırılmasıdır ve GPU programlamanın temelini oluşturur. Görev paralelliği (task parallelism) ise, farklı hesaplamaların paralel yürütülmesidir.

  • Concurrency için Tasarım Desenleri: Aktör Modeli, Üretici-Tüketici (Producer-Consumer), İş Parçacığı Havuzu (Thread Pool), Asenkron/Olay Tabanlı Programlama.
  • Parallelism için Tasarım Desenleri: MapReduce, İş Parçacığı Başına Bir Örnek (Fork-Join), Paralel Döngüler (Parallel Loops), Dağıtık Paylaşımsız Bellek (Distributed Shared-Nothing).
  • Kesişen Yaklaşımlar: Paralel programlama çatıları (OpenMP, TBB), doğal olarak eşzamanlı işlemleri paralel donanımda çalıştırmak için soyutlama sağlar.

Pratikte, bir uygulama geliştiricisi, kullanıcı arayüzünün (UI) yanıt vermeye devam etmesini sağlamak için ağ çağrılarında eşzamanlılık (concurrency) kullanırken, bir veri bilimci büyük bir matris çarpımını hızlandırmak için paralellik (parallelism) kullanır. Seçilecek yaklaşım, problem alanının doğasına, performans hedeflerine ve mevcut donanım altyapısına bağlıdır. Modern yazılım mimarileri, mikroservisler gibi, genellikle her iki konsepti de bünyesinde barındırır: servisler birbirinden bağımsız ve eşzamanlı olarak çalışır (concurrency), ve her bir servis kendi içinde paralel algoritmalardan faydalanabilir (parallelism).

Zorluklar ve Çözüm Stratejileri

Concurrency'nin getirdiği en temel zorluk yarış koşullarıdır (race conditions). İki veya daha fazla iş parçacığı, paylaşılan bir veriye aynı anda erişip değiştirdiğinde, işlem sırasına bağlı olarak öngörülemeyen ve yanlış sonuçlar ortaya çıkar. Bu, belirsizlik (non-determinism) kaynağıdır ve hata ayıklaması son derece zordur. Bir diğer kritik sorun ise kilitlenmelerdir (deadlocks). İki veya daha fazla iş parçacığının, ilerlemek için birbirlerinin elindeki kaynağı beklemeleri ve dolayısıyla sonsuz bir beklemeye girmeleri durumudur.

Bu sorunlara karşı geliştirilen en yaygın mekanizma senkronizasyon araçlarıdır. Mutex'ler (karşılıklı dışlama) ve semaforlar, kritik bölümlere (critical sections) erişimi serileştirerek veri tutarlılığını korur. Ancak, bu araçların yanlış kullanımı performans düşüşüne (aşırı kilitleme) veya yeni kilitlenmelere yol açabilir. Daha modern bir yaklaşım, paylaşılan değişken durumu ortadan kaldırmaktır. Değişmez (immutable) veri yapıları kullanmak, veri hiçbir zaman değişmediği için yarış koşullarını doğal olarak engeller. Mesaj geçişli sistemler (Actor model, CSP) ise iş parçacıklarının doğrudan bellek paylaşmak yerine mesajlaşmasını sağlayarak senkronizasyon ihtiyacını büyük ölçüde azaltır.

Parallelism'in önündeki temel engeller ise Amdahl Yasası ile teorik olarak sınırlanmıştır. Yasaya göre, bir programın yalnızca 'P' oranında paralelleştirilebilir kısmı varsa, ne kadar çok işlemci kullanılırsa kullanılsın elde edilebilecek maksimum hızlanma 1/(1-P) ile sınırlıdır. Pratikte ise veri bağımlılıkları (data dependencies) ve bellek erişim darboğazları (memory bandwidth bottlenecks) önemli sorunlardır. İşlemciler paralel çalışsa da, ortak bir sistem belleğine erişim rekabeti performansı ciddi şekilde kısıtlayabilir.

Paralel performans sorunlarının çözümü, dikkatli bir algoritma ve veri yapısı tasarımını gerektirir. Yerellik (locality) ilkesini gözetmek, verinin mümkün olduğunca işlemci önbelleğinde kalmasını sağlayarak bellek gecikmesni azaltır. İş yükünü eşit dağıtmak için dinamik iş yükü dengeleme (dynamic load balancing) algoritmaları kullanılır. Ayrıca, önbellek dostu (cache-friendly) veri düzenleri ve azaltılmış/gevşetilmiş tutarlılık (relaxed consistency) modelleri gibi düşük seviyeli optimizasyonlar, paralel verimliliği artırmada hayati öneme sahiptir. Sonuç olarak, concurrency ve parallelism'in zorlukları, birbirinden farklı ancak derinlemesine bağlantılıdır. Sağlam bir eşzamanlı tasarım olmadan, paralel yürütüm güvenilir olamaz; paralel donanımın kapasitesini anlamadan ise, eşzamanlı yazılım optimal performansa ulaşamaz.