Bu makalede, C# programlama dilinde kullanılan threading ve parallel programming tekniklerine değinilmiştir Threading, birden fazla işlemin aynı anda çalıştırılmasına imkan tanıyan bir tekniktir Parallel programming ise büyük veri işleme gibi yüksek performans gerektiren işlemlerde CPU kaynaklarının etkin bir şekilde kullanılmasını sağlar PLINQ ise LINQ sorgularının paralel olarak çalıştırılmasına olanak tanıyan bir tekniktir Concurrent sınıfları ve Monitor sınıfı gibi araçlar, kodların thread-safe olmasını sağlarken ThreadPool sınıfı da işlemlerimizde kullanabileceğimiz bir araçtır Parallel programming kullanırken, hangi yöntemin ve yapıların kullanılacağına dikkat etmek önemlidir

Bu makale, C# programlama dilinin iki önemli kavramı olan threading ve parallel programming ile ilgilidir. Burada, C# kodu yazarak yeni threadlerin nasıl oluşturulacağı ve parallel programming kullanarak C# kodunun nasıl optimize edilebileceği ele alınacaktır. Ayrıca, Concurrent sınıfları da dahil olmak üzere parallel programming için farklı araçlar ve teknikler incelenecektir.
C# programlama dilinde Threading, birden fazla işlemin bir arada çalıştırılmasına izin veren bir tekniktir. Bu teknik sayesinde, CPU işlemleri parçalara bölerek birden fazla thread oluşturulabilir ve bu threadler aynı anda işlenebilir. Parallel programming ise artan iş yüküne karşılık gelen daha fazla kaynak kullanımını sağlamak için tasarlanmıştır. Bu sayede, kod blokları aynı anda birden fazla işlemci tarafından işlenebilir ve programın performansı artırılabilir.
Parallel programming kullanırken, PLINQ ve Task Parallel Library (TPL) gibi araçların yanı sıra Concurrent sınıfları kullanarak kodun thread-safe hale getirilmesi sağlanabilir. Bu sınıflar, aynı anda birden fazla thread tarafından erişilebilen yapılar sağlayarak kodun daha etkili ve verimli çalışmasını sağlar.
İşletim sistemi tarafından önceden oluşturulmuş bir thread havuzu olan ThreadPool sınıfı da threading teknikleri içinde kullanılabilen bir araçtır. Nesne yönelimli programlama konusunda C# ile ilgili bilgi sahibiyseniz, ThreadPool'un nasıl kullanılabileceği hakkında daha rahat bir fikir sahibi olabilirsiniz.
ConcurrentBag, ConcurrentDictionary ve ConcurrentQueue gibi araçlar da parallel programming tekniklerinde kullanabileceğiniz yapılar arasındadır. Bu yapılar sayesinde, farklı threadler tarafından erişilebilen koleksiyonlar, sözlükler ve kuyruklar oluşturulabilir. Bu yapılara aynı anda birden fazla thread tarafından erişilmesine izin veren kodlar yazarak, kodların thread-safe olmasını sağlayabilirsiniz.
Thread Nedir?
Thread, bir işlemcisindeki bir işlem kümesidir ve bu işlemci tarafından işlenir. C# ile yeni bir thread oluşturmak oldukça kolaydır. Yeni bir thread oluşturmak için, System.Threading.Thread sınıfını kullanabilirsiniz.
Bir thread oluşturmak için, Thread sınıfındaki nesneye parametre olarak bir işlev vermeniz gerekir. Bu işlev, thread'in çalıştırması gereken kodu içerir. Aşağıdaki örnek, bir thread oluşturmanın en temel yolu gösterir:
ThreadStart start = new ThreadStart(Ipucu); Thread thread = new Thread(start); thread.Start();
Yukarıdaki örnekte, Ipucu adlı bir işlev oluşturulur ve ThreadStart sınıfı kullanılarak başlatılır. Sonra, oluşturulan Thread nesnesi start değişkeniyle başlatılır. Thread, sonunda Start () yöntemi çağrıldığında çalıştırılır.
Bir başka kullanışlı özellik, thread'in adının ayarlanabilmesidir. Adını ayarlamak için, Name özelliğine yeni bir dize atayabilirsiniz. Bu özellik, uygulamanızda birden fazla thread kullanıyorsanız, hangi thread'in hangi kod parçasını çalıştırdığınızı takip etmenize olanak tanır.
Parallel Programming Nedir?
Parallel programming, tek bir CPU üzerinde birden fazla iş parçasının aynı anda işlemesi için tasarlanan bir tekniktir. Bu teknik, özellikle büyük veri işleme gibi yüksek performans gerektiren işlemlerde oldukça faydalıdır. C# ile parallel programming yapmak için birçok farklı yöntem bulunmaktadır.
Parallel.ForEach() metodu, bir koleksiyon üzerinde çalışırken her bir eleman için ayrı bir thread oluşturarak parallel programming yapma imkanı sağlar. Bu sayede, verileri hızlı bir şekilde işleyebiliriz. Ayrıca, Parallel.Invoke() metoduyla da belirtilen kod bloklarını aynı anda çalıştırabiliriz.
Bununla birlikte, parallel programming kullanırken dikkat etmemiz gereken bazı faktörler bulunmaktadır. Özellikle, threadler arasında kaynak paylaşımı konusunda özen göstermemiz gerekir. Bu nedenle, Monitor sınıfı kullanarak kritik bölümleri kilitlememiz veya Concurrent sınıflarını kullanarak thread güvenliği sağlamamız gerekebilir.
Parallel programming ile yapılacak işlemlerde, hangi yöntemin kullanılacağına ve hangi senaryolarda kullanılacağına dikkat edilmesi önemlidir. Bu sayede, kodlarımız daha optimize bir şekilde çalışabilir ve yüksek performanslı uygulamalar geliştirebiliriz.
PLINQ Nedir?
Parallel LINQ (PLINQ), LINQ'ın parallel çalışan bir sürümüdür. PLINQ, birden fazla CPU çekirdeği veya işlemci olduğunda ve işleme zamanı önemli olduğunda işlemci kaynaklarını optimize etmek için kullanılır. PLINQ, LINQ sorgularının etkinliğini artırarak büyük veri kümelerindeki sorgulama sürelerini büyük ölçüde azaltır.
PLINQ, CPU çekirdekleri arasında LINQ sorularını dağıtarak ve her çekirdekte aynı anda birden fazla sorguyu işleyerek birden fazla çekirdekten yararlanır. Bu, hızlı ve etkili bir arama sorgusuna izin verir. PLINQ'in LINQ'a göre bir diğer avantajı da, verilerin işlenmesini daha esnek ve daha optimizasyon yapılabilir hale getirmesidir.
PLINQ, C# kodlama çalışmalarında, performansı optimize etmek için kullanılan bir tekniktir. PLINQ ile verimliliği artırmak ve paralel olarak sorgulama yapmak mümkündür. PLINQ'nun kullanımı ve avantajları hakkında daha fazla bilgi edinmek için aşağıdaki tabloyu inceleyebilirsiniz.
PLINQ Avantajları | PLINQ Dezavantajları |
---|---|
|
|
Task Parallel Library Nedir?
Task Parallel Library (TPL), C# kodunun performansını artırmak için kullanılabilecek bir parallel programming çerçevesidir. Bu kütüphane, .NET Framework 4.0 ve sonraki sürümlerinde yer almaktadır. TPL’in yararlarından bazıları şunlardır:
- Thread yönetimi ve koordinasyonu gibi zor işlemler TPL tarafından otomatik olarak yönetilir. Bu sayede geliştiriciler, kodları son derece basit ve anlaşılır bir şekilde yazabilirler.
- TPL, birden fazla CPU çekirdeği olduğunda otomatik olarak parallel programlama yapar ve böylece işlem gücü artar.
- TPL, kodun okunabilirliğini artırır ve hataları azaltır. Bu sayede kod geliştirme ve bakımı daha kolay hale gelir.
TPL, Task adı verilen iş parçaları üzerine kuruludur. Bir Task , bir iş parçasının tek bir örneğidir. TPL, birden fazla Task 'ı koordine ederek parallel programming işlemlerini gerçekleştirir. TPL kullanımında, System.Threading.Tasks kütüphanesi referans olarak eklenmelidir.
Bir Task oluşturmak için, Task sınıfının Run() yöntemi kullanılabilir. Örneğin:
|
Bu kod, bir Task<string> nesnesi oluşturur ve "Merhaba, Dünya!" metnini döndüren bir iplik (thread) oluşturur. TPL, bu Task 'ı otomatik olarak parallel olarak çalışır.
Bir Task , bir değer döndürebilir veya bir değer döndürmeyebilir. Bu, Task<TResult> veya Task sınıfına göre belirlenir. Bir Task<TResult> örneği kullanılarak bir değer döndürülebilir. Bir Task örneği kullanıldığında ise, bir değer döndürme zorunluluğu yoktur.
Bir Task , ContinueWith() yöntemi kullanılarak başka bir Task ile birleştirilebilir:
|
Bu kodda, task1 değişkeni oluşturulur ve "Merhaba," metnini döndüren bir Task<string> nesnesi oluşturulur. Daha sonra, task2 değişkeni oluşturulur ve task1 'in sonucuna " Dünya!" ekleyen bir iplik (thread) oluşturulur.
Parallel Sınıfı Nedir?
Parallel sınıfı, C#'ın .NET Framework'de bulunan bir sınıfıdır. Bu sınıf sayesinde, parallel programming yaparken iş parçacıkları arasında çalışma dağıtılabilir ve CPU kaynakları daha etkili kullanılabilir.
C# kodu içerisinde, Parallel.ForEach() metodu kullanılarak daha kolay bir şekilde parallel programming yapılabilir. Bu metot, bir koleksiyon üzerinde, tüm elemanların işleminin aynı anda başlatılmasını sağlar. İşlemler, CPU kaynaklarına göre parçalanabilir ve hızlandırılabilir. Ayrıca, Parallel.Invoke() metodu kullanılarak birden fazla işlem eşzamanlı olarak çalıştırılabilir.
Parallel sınıfının kullanımı oldukça basit ve C# kodunda bulunan LINQ gibi C# tarafından sağlanan faydalı bir araçtır. C# kodu parallel programming kullanarak çalışmasında performans artışı sağlamak isteyenler, Parallel sınıfının kullanımını mutlaka öğrenmelidir.
ThreadPool Nedir?
ThreadPool, C# ile oluşturulan yeni threadlerin gereksiz yere oluşmasını önleyerek, var olan threadleri yeniden kullanımını sağlayan bir kuyruktur. ThreadPool sayesinde geliştiriciler, hafif işlemler için yeni threadler oluşturmaya gerek kalmadan, var olan threadleri kullanarak performansı artırabilirler.
ThreadPool sınıfı, .NET Framework tarafından sağlanmaktadır. Bu sınıf kullanılarak bir thread havuzu oluşturulur ve threadler bu havuzdan alınır. Havuzda belirli bir sayı kadar thread bulunabilir ve herhangi bir yerden yeni threadler oluşması engellenir. {Kaynak 1}
ThreadPool sınıfı, ayrıca bir metoda bağlanarak, method'un yapacağı işlemleri thread havuzundaki threadlerle eş zamanlı olarak gerçekleştirilmesine olanak sağlar. Bu sayede, işlemci performansı arttırılır ve program daha hızlı bir şekilde çalışır. Programcılar, ThreadPool sınıfını kullanarak, CPU'yu daha etkin bir şekilde kullanmak için çalışan uygulamaları optimize edebilirler.
Ayrıca, ThreadPool sınıfı kullanarak, birden fazla işlemi eşzamanlı olarak gerçekleştirebilirsiniz. Örneğin, bir resim sıkıştırma işleminin yanı sıra, farklı bir resim dosyasının yedeğinin alınması işlemlerini de aynı anda gerçekleştirebilirsiniz. İşlemler paralel olarak gerçekleştiği için zaman tasarrufu sağlanır.
ThreadPool sınıfının kullanımının yanı sıra, dikkat edilmesi gereken bir diğer nokta da, threadlerin ölümcül bir hata yapması durumunda, thread havuzundan çıkartılması gerektiğidir. Ölümcül bir hata oluştuğunda, ThreadPool sınıfı tarafından yönetilen threadlerin continuosly hata yapması, uygulamayı kapatır. Bu nedenle, ThreadPool sınıfının kullanımı özellikle özenle ele alınmalı ve hata durumlarına hazırlıklı olunmalıdır.
Concurrent Sınıfları Nedir?
Concurrent sınıflar, birden fazla thread tarafından eşzamanlı olarak kullanılabilen sınıflardır. Günümüzde threading ve parallel programming deyince akla gelen ilk kavramlar arasındadır. Bu sınıfların kullanımı sayesinde paralel olarak çalışan işlemlerle verimlilik arttırılabildiği gibi veri bütünlüğü de korunmuş olur.
Concurrent sınıflarının en çok tercih edilen üç türü vardır; ConcurrentBag, ConcurrentDictionary ve ConcurrentQueue.
Concurrent sınıflarının her biri, farklı amaçlar için tasarlanmıştır. ConcurrentBag, bir koleksiyon türüdür ve aynı anda birden fazla thread tarafından kullanılabilir. ConcurrentDictionary, eş zamanlı olarak birden fazla thread tarafından kullanılabilen bir sözlüktür. ConcurrentQueue ise threadler için güvenli bir kuyruktur ve eş zamanlı olarak birden fazla thread tarafından kullanılabilir. Bu özellikleri sayesinde, threadler arasında güvenli bir işbirliği sağlanabilir ve paralel olarak çalışan işlemlerle toplam işlem süresi azaltılabilir.
Özellikle büyük ölçekli projeler için, verimliliği arttırmak ve bütünlüğü korumak adına Concurrent sınıfları kullanmak oldukça önemlidir. Bu nedenle, C# ile çalışırken threading ve parallel programming kavramlarına hakim olmak, verimliliği arttırmak adına oldukça faydalıdır.
ConcurrentBag?
ConcurrentBag?
ConcurrentBag, C# 4.0 ve üzeri sürümlerde bulunan bir koleksiyon sınıfıdır. ConcurrentBag, birden fazla thread tarafından eşzamanlı olarak kullanılabilen bir koleksiyondur. Farklı threadlerin aynı anda eleman eklemesi ve çıkarması mümkündür. ConcurrentBag, IEnumerable interface'ini implement eder ve standart bir koleksiyon sınıfı gibidir.
ConcurrentBag kullanımı oldukça basittir. Öncelikle, ConcurrentBag sınıfının instance'ı oluşturulur. Ardından, Add () metodunu kullanarak elemanlar ConcurrentBag'e eklenir. Elemanları sırayla değil, paralel olarak eklemesi üzerinde durun. ConcurrentBag içerisinde aynı elemandan birden fazla olabilir, ancak elemanlarının sıralaması sağlanmaz.
Bir ConcurrentBag örneği aşağıdaki gibi tanımlanabilir:
Kod |
---|
ConcurrentBag<string> bag = new ConcurrentBag<string>(); |
Eleman ekleme işlemi Add() metodu kullanılarak gerçekleştirilir.
Kod |
---|
bag.Add("eleman1"); bag.Add("eleman2"); bag.Add("eleman3"); |
ConcurrentBag içerisinde RandomAccess ve IndexOf metodları bulunmadığından elemanlara erişim GetConsumingEnumerable() ile yapılır.
Kod |
---|
foreach (var eleman in bag.GetConsumingEnumerable()) { Console.WriteLine(eleman); } |
Bu kod, ConcurrentBag içerisindeki elemanları tek tek döndürür.
ConcurrentBag sınıfı, birden fazla threadin aynı anda farklı elemanları eklemesi ve çıkarması durumunda verimliliği artırırken hata ile karşılaşma olasılığını da azaltır.
ConcurrentDictionary?
ConcurrentDictionary, birden fazla thread tarafından eşzamanlı olarak kullanılabilen bir sözlüktür. Bu sınıf, Thread-Safe Dictionary sınıfının eş zamanlı kullanımı için tasarlanmıştır. ConcurrentDictionary, birden fazla ekleme ve okuma işlemi yapabilen bir sözlük sınıfıdır.
Bu sınıfın kullanımı oldukça basittir. Öncelikle, sınıfın ad alanını eklemek gerekir:
Kod: | Sonuç: |
---|---|
using System.Collections.Concurrent; |
Ardından, ConcurrentDictionary nesnesi oluşturulmalıdır. Aşağıdaki örnekte, ConcurrentDictionary nesnesi 'myDictionary' adıyla oluşturulmuştur:
Kod: | Sonuç: |
---|---|
ConcurrentDictionary<string, int> myDictionary = new ConcurrentDictionary<string, int>(); |
Bu örnekte, ConcurrentDictionary'nin anahtarlarının string ve değerlerinin int türünde olduğu belirtilmiştir.
ConcurrentDictionary'ye ekleme işlemi yapmak için, AddOrUpdate metodu kullanılabilir. Bu metot, sözlüğe bir anahtar ve bir değer ekler veya mevcut bir anahtarın değerini günceller. Örnek kullanım aşağıda verilmiştir:
Kod: | Sonuç: |
---|---|
myDictionary.AddOrUpdate("elma", 1, (key, oldValue) => oldValue + 1); |
Bu örnekte, 'elma' anahtarı ve 1 değeri sözlüğe eklenir veya 'elma' anahtarına sahip bir değer varsa, değeri 1 artırılır.
ConcurrentDictionary'den bir değer okumak için ise, TryGetValue metodu kullanılabilir. Bu metot, sözlükteki belirtilen anahtarın değerini döndürür. Aşağıdaki örnekte, 'elma' anahtarına sahip değerin okunması gösterilmiştir:
Kod: | Sonuç: |
---|---|
int value; | |
if (myDictionary.TryGetValue("elma", out value)){ Console.WriteLine("elma = " + value);} | elma = 2 |
Bu örnekte, 'elma' anahtarına sahip değer, TryGetValue metodu ile okunmuştur.
ConcurrentDictionary, birden fazla thread tarafından eş zamanlı olarak kullanılabilmesi sayesinde, thread güvenliği açısından oldukça güvenlidir. Bu nedenle, birden fazla thread'in çalıştığı uygulamalarda, ConcurrentDictionary kullanmak oldukça yararlı olacaktır.
ConcurrentQueue Nedir?
ConcurrentQueue sınıfı, C# programlama dilinde yer alan kuyruk yapısıdır. Bu kuyruk yapısı, birden fazla thread tarafından eşzamanlı olarak erişilebilir olması sebebiyle thread güvenliği konusunda büyük bir avantaj sağlar.
ConcurrentQueue sınıfı, öğelerin eklenmesi ve çıkarılması için iki ana yöntem sunar: Enqueue ve TryDequeue. Enqueue yöntemi, ConcurrentQueue sınıfına bir öğe ekler ve TryDequeue yöntemi, en üstteki öğeyi ConcurrentQueue sınıfından çıkarır. Bu işlemler, birden fazla thread tarafından eşzamanlı olarak gerçekleştirilir ve kuyruk yapısının güvenliği sağlanır.
Bununla birlikte, ConcurrentQueue sınıfının birden fazla öğe eklenmesine ve çıkarılmasına izin veren Peeking, Contains ve CopyTo gibi yöntemleri de bulunmaktadır. Peeking yöntemi, ConcurrentQueue sınıfının en üstteki öğesini döndürür, Contains yöntemi, belirli bir öğenin kuyrukta olup olmadığını sorgularken, CopyTo yöntemi ise ConcurrentQueue sınıfındaki öğeleri belirli bir diziye kopyalar.
ConcurrentQueue sınıfı, threadlerin kullanımı için güvenli bir kuyruk yapısı sunar. Başka bir deyişle, birden fazla thread tarafından eşzamanlı olarak erişilebilen bu kuyruk yapısı, verilerin hatalı yada eksik işlenmesi riskini ortadan kaldırır.