1. Giriş
Paralel hesaplama, bir bilgisayar veya hesaplama sistemi içindeki çoklu işlemcilerin veya işlem birimlerinin eşzamanlı olarak çalıştığı bir hesaplama modelidir. Geleneksel olarak, bilgisayarlar tek bir işlemciye sahiptir ve işlemler sırayla gerçekleştirilir. Ancak, paralel hesaplama sayesinde, birden fazla işlemci aynı anda çalışarak büyük miktarda veriyi daha hızlı işleyebilir ve karmaşık problemleri daha verimli bir şekilde çözebilir.
Paralel hesaplama, şu avantajları sağlar:
- Daha hızlı hesaplama: İşlemcilerin eşzamanlı çalışması sayesinde, paralel hesaplama, büyük veri kümesini parçalara bölerek her bir parçayı farklı işlemcilere atayarak işlem süresini büyük ölçüde azaltabilir.
- Yüksek performans: Paralel hesaplama, karmaşık hesaplamalarda yüksek performans elde ederek bilimsel simülasyonlar, veri tabanı sorgulamaları, görüntü işleme ve yapay zekâ gibi yoğun işlem gerektiren uygulamalarda önemli bir avantaj sağlar.
- Ölçeklenebilirlik: Paralel hesaplama, işlem gücü ihtiyacı arttıkça sistemi kolayca ölçeklendirebilme yeteneğine sahiptir. Yani, daha fazla işlemci eklenerek hesaplama kapasitesi artırılabilir.
Paralel hesaplama, farklı düzeylerde uygulanabilir: Tek bir işlemci üzerinde birden çok çekirdek kullanarak (multicore), birden fazla işlemcinin birbirine bağlı olduğu çoklu işlemcili sistemler (multi-processor) veya ağ üzerinden dağıtılmış çoklu bilgisayarlar (cluster) şeklinde olabilir.
Ancak, paralel hesaplama, bazı durumlarda karmaşık hale gelebilir ve programlaması zor olabilir. Veri bağımlılığı, senkronizasyon, iletişim, eşzamanlılık sorunları gibi zorluklarla karşılaşılabilir. Bu nedenle, paralel hesaplama, uygun algoritma tasarımı ve dikkatli işlemci/çekirdek yönetimi gerektirir.
2. İşlem (Process) ve İş Parçacığı (Thread)
Process | Thread |
---|---|
Bilgisayar sisteminde çalışan bir programdır. | Process içinde çalışan yürütme birimleridir. |
Her process’in kendi bellek alanı vardır. | Bir process içinde diğer thread’lerle paylaşılan ortak bellek alanını kullanırlar. |
Her process’in bellek alanı ayrı olduğu için processler birbirleriyle haberleşmek için inter-process communication mekanizmaları kullanır. | Diğer threadler’le ortak bellek alanı kullanıldığı için threadlerin birbiriyle haberleşmeleri daha kolaydır. |
Bir process oluşturmak thread oluşturmaya göre daha yavaş ve daha çok maliyetlidir. | Bir thread oluşturmak ve yönetmek process oluşturmaya göre daha hızlı ve az maliyetlidir. |
Paralel programlama için process veya thread tercihi çözülecek probleme ve kullanılacak sistemlere göre değişmektedir.
Process oluşturmanın daha avantajlı olduğu yönler:
- İzolasyon: İşlemler, kendi adres uzayına sahip olduğundan birbirlerinden tamamen izole edilebilir. Bu, bir işlemin hatalı çalışması veya çökmesi durumunda diğer işlemlerin etkilenmeyeceği anlamına gelir. Aynı zamanda, işlemler, işletim sistemi tarafından sağlanan mekanizmaları kullanarak birbirlerine müdahale etmeden çalışabilir.
- Güvenlik: İşlemler, kendi özel bellek alanlarına sahip olduklarından, bilgi güvenliğini artırabilirler. Bir işlem, kendi veri ve koduna diğer işlemlerin erişimini sınırlandırarak kötü niyetli saldırılardan kendisini koruyabilir.
- Daha İyi Ölçeklenebilirlik: İşlemler, farklı fiziksel işlemciler ve çekirdekler arasında daha iyi bir ölçeklenebilirlik sağlar. Çünkü işlemler, işlem gücünü arttırmak için daha fazla fiziksel işlemciyi veya çekirdeği kullanabilir.
Örneğin Google Chrome’da her bir sekme bir process’tir. Böylelikle sekmeler birbirinden izole olurlar. Bir sekmenin yanıt vermemesinden veya çökmesinden diğer sekmeler etkilenmemektedir ve bir sekmedeki kötü amaçlı kodlar diğer sekmelere erişemez.
Thread oluşturmanın daha avantajlı olduğu yönler:
- Daha Hafif ve Daha Hızlı Oluşturma: Threadler, işlemlere kıyasla daha hafif ve daha hızlı bir şekilde oluşturulabilir ve yönetilebilir. İşlem oluşturmak, işletim sistemi tarafından yeni bir işlem yaratmak ve bu işlem için ayrı bir bellek alanı oluşturmak gibi daha fazla maliyet ve süreç gerektirirken, threadler, bir işlem içinde çalıştıkları için işlem oluşturmak yerine daha hızlı bir şekilde başlatılabilirler.
- Daha Az Bellek Tüketimi: Threadler, bir işlemle paylaşılan ortak bir bellek alanını kullanırken, işlemler kendi özel bellek alanına sahiptir. Bu nedenle, aynı görevleri yürüten işlemlere kıyasla daha az bellek tüketirler ve daha verimli bir bellek yönetimi sağlarlar.
- Daha Etkili İletişim: Threadler, aynı işlem içinde çalıştıkları için, iş parçacıkları arasında veri paylaşımı daha kolaydır. Bellek alanını paylaşarak verileri doğrudan değiştirebilir ve iletişim için ekstra mekanizmalara ihtiyaç duymazlar.
- İşletim Sistemi Kaynakları: İşlem oluşturmak işletim sistemi üzerinde daha fazla yük oluştururken, threadler daha hafif bir yüke neden olur. Bu, aynı anda çok sayıda paralel işlemi yönetmenin daha verimli bir şekilde gerçekleştirilmesini sağlar.
3. Paralel Programlamada Karşılaşılan Zorluklar
3.1. Race Condition
Race condition, birden fazla iş parçacığının veya işlemin, paylaşılan bir kaynağı (örneğin, bir değişken, bellek alanı, dosya veya veritabanı) eşzamanlı olarak okuyup yazması durumunda, beklenmedik ve hatalı sonuçların oluştuğu durumlardır.
Race condition, aynı kaynağa birden fazla iş parçacığının erişebileceği bir yarış durumu olarak düşünülebilir. İş parçacıkları, aynı kaynağı değiştirme sırasını garanti etmediğinden, beklentiler dışı sonuçlar ortaya çıkabilir. Bu durum, programın deterministik olmaması ve her çalıştırıldığında farklı sonuçlar üretmesi gibi hatalara yol açabilir.
Örnek bir race condition durumunda, iki iş parçacığı aynı değişkeni okuyup değiştirme işlemi gerçekleştirirken, bir iş parçacığı değişkeni okurken diğer iş parçacığı değişkeni değiştirir. Bu durumda sonuç, her iki iş parçacığının işlemlerine bağlı olarak beklenmedik bir değer olabilir.
Race condition'lar, paralel programlama yaparken dikkat edilmesi gereken önemli bir konudur. Race condition'ların önüne geçmek için iş parçacıkları arasında senkronizasyon mekanizmaları kullanmak, kritik bölge (critical section) adı verilen paylaşılan kaynaklara aynı anda sadece bir iş parçacığının erişmesini sağlamak yaygın olarak tercih edilen yöntemlerdir. Bu şekilde, paylaşılan kaynaklar üzerindeki eşzamanlı erişim problemleri önlenir ve programın güvenli ve doğru bir şekilde çalışması sağlanır.
3.1.1. Race Condition için Senkronizasyon Metotları
- Mutex Kilidi: Kritik bölgeye girmeden önce belirli bir kilit (mutex) alınır ve iş bittikten sonra kilit bırakılır. Diğer iş parçacıkları, kilidin açılmasını bekler ve böylece paylaşılan kaynağa sırayla erişilir.
- Semaforlar: Semaforlar, bir kaynağın eşzamanlı erişimini kontrol etmek için kullanılan sayısal bir veri yapısıdır. Bir semafor, belirli bir kaynağın mevcut sayısını temsil eder. İş parçacıkları, kaynağı kullanmak istediklerinde semaforu azaltır (acquire) ve kaynağı bırakırlarken semaforu arttırır (release). Semaforların değeri, kaynağın mevcut durumunu gösterir ve izin verilen maksimum eşzamanlı erişim sayısını belirler.
3.2. Process’ler Arası Veri Paylaşımı
Her bir process’in bellek alanı ayrı ve izole olduğu için process’ler arasında veri paylaşımı aşağıdaki tekniklerle gerçekleştirilebilir:
- Pipe: Pipe, iki işlem arasında doğrudan bir yönlü (unidirectional) veya çift yönlü (duplex) veri akışı sağlayan basit bir IPC mekanizmasıdır. Bir işlem veri yazarken, diğer işlem bu veriyi okuyabilir. Pipe, çoğunlukla parent ve child işlemler arasında veri iletimi için kullanılır. Eğer aynı ucu birden fazla process kullanırsa pipe’ın içindeki verilerde bozulma olabilir.
- Message Queue (Mesaj Kuyruğu): Mesaj kuyruğu, bir işlemin mesajları diğer işlemlere gönderdiği ve alıcının mesajları kuyrukta beklettiği bir IPC yöntemidir. Mesaj kuyruğu, veri alma ve veri gönderme işlemlerini asenkron olarak yapabilme yeteneğine sahiptir.
- Shared Memory (Paylaşılan Bellek): Paylaşılan bellek, farklı işlemler arasında bellek alanını paylaşma imkânı sağlayan bir IPC mekanizmasıdır. Paylaşılan bellek sayesinde, işlemler aynı bellek alanına yazabilir ve diğer işlemler bu bellek alanını okuyabilir.