İlkay İlknur

just a developer...

.NET Framework 4.0 - Parallel.For ve Parallel.Foreach ile Döngülerin Paralel Olarak İşletilmesi

Merhaba Arkadaşlar,

.NET Framework 4.0 ile beraber gelecek olan paralel programlama altyapısına göz atacağımız ilk yazımızda basit olarak for ve foreach döngülerini nasıl paralel bir şekilde çalıştırabiliriz bunu inceliyor olacağız. Paralel olarak for ve foreach döngülerini çalıştırmak için TPL(Task Parallel Library) içerisinde bulunan metotları kullanıyor olacağız. TPL içerisinde bulunan For ve Foreach metotları sayesinde düngülerin paralel bir şekilde işletilmesi için gereken tüm işlemler TPL tarafından otomatik olarak ele alınmaktadır. Bizim yapmamız gereken ise sadece ilgili değerleri vermek. Öncelikle for ve foreach döngülerini nasıl paralel bir şekilde çalıştırabiliriz bunu incelemeye çalışalım. Paralel döngüler için Parallel tipi içerisinde bulunan For ve Foreach metotlarını kullanıyoruz. For metodunun parametrelerine bakarsak.

Parallel.For(int fromInclusive, int toExclusive, Action<int> body)

  • fromInclusive : For döngüsünün başlayacağı değer.
  • toExclusive : For döngüsünün döneceği son değer.
  • body : For döngüsünün içerisinde yapılacak işlemler.
Body parametresinin tipi Action<int> olarak görülmektedir. Yani biz bu parametre için C# 3.0 ile beraber gelen lambda ifadelerini kullanabiliriz.Wink Temel kullanım ise şu şekilde:
 //0'dan 9'a kadar dönen for döngüsü
Parallel.For(0,10,p=>
{
   //İşlemler
});
Foreach metoduna baktığımızda ise yine for döngüsüne benzer bir imza ile karşılaşıyoruz. Parallel.Foreach(IEnumerable<TSource> source, Action<TSource> body)
  • source : Foreach işlemi boyunca içerisinde dolaşacağımız IEnumerable arayüzünü implemente etmiş olan koleksiyon
  • body : Foreach döngüsü içerisinde ele alacağımız işlemler.
Foreach döngüsünün de temel kullanımı şu şekilde:
IEnumerable<int> numbers = Enumerable.Range(1,1000);
Parallel.ForEach(numbers, p =>
    {
        //numbers hangi tipi taşıyan koleksiyon ise 
       //p parametresi de o tipte
      //işlemler
    });
Basit olarak for ve foreach döngülerinin nasıl parallelize edildiğini görmüş olduk. Şimdi ise bir örnek üzerinde for ve foreach döngülerini kullanalım ve biraz daha derine inerek ne gibi işlemler gerçekleşiyor ve döngüler nasıl işletiliyor incelemeye çalışalım. Aşağıdaki gibi bir Çalışan sınıfımız olduğunu düşünelim ve çalışanların toplam alacağı ücretleri paralel bir şekilde hesaplayalım ve daha sonra ekrana yazdıralım.
public class Calisan
{
    public int ID { get; set; }
    public double SaatlikUcret { get; set; }
    public double ToplamCalisma { get; set; }
}
Elimizde çeşitli değerler ile yaratılmış olan bir Calisan listesi olduğunu düşünelim ve paralel foreach döngüsü ile gerekli hesaplamayı yaparak Console'a sonuçları yazdıralım.
static void Hesapla(List<Calisan> calisanlar)
{
    Parallel.ForEach(calisanlar, calisan =>
            {
               double total = calisan.SaatlikUcret * calisan.ToplamCalisma;
               Console.WriteLine("{0} numaralı çalışanın alacağı toplam ücret:{1}\n",calisan.ID,total);
            });
}
Son olarak listeyi yaratacağımız ve çeşitli çalışan nesneleri ile doldurup Hesapla metodunu çağıracağımız Main metot ise şu şekilde.
static void Main(string[] args)
{
    List<Calisan> calisanlar = new List<Calisan>()
    {
        new Calisan(){ID=1,SaatlikUcret=10,ToplamCalisma=30},
        new Calisan(){ID=2,SaatlikUcret=12,ToplamCalisma=34},
        new Calisan(){ID=3,SaatlikUcret=8,ToplamCalisma=38},
        new Calisan(){ID=4,SaatlikUcret=14,ToplamCalisma=39},
        new Calisan(){ID=5,SaatlikUcret=18,ToplamCalisma=37},
    };
    Hesapla(calisanlar);
}
Uygulamayı çalıştırıp sonuçlara bakarsak. Gördüğümüz gibi listeye çalışan nesnelerini ID'leri sıralı olacak şekilde eklememize rağmen foreach döngüsü içerisinde farklı sıralarda işletildiğini görmekteyiz. Uygulamayı her çalıştırdığımızda ise sürekli olarak farklı sonuçlarla karşılaşmamız oldukça normaldir. Bunun nedeni ise foreach döngüsü içerisinde paralel işlemek için yaratılan threadlerin işlemci tarafından farklı sıralarda işleme alınmasıdır. Bunu görmek için Hesapla metodunu aşağıdaki gibi değiştirip uygulamayı yeniden çalıştırırsak daha kolay bir şekilde threadleri takip edebiliriz.
static void Hesapla(List<Calisan> calisanlar)
{
    Parallel.ForEach(calisanlar, calisan =>
            {
                 int threadid = Thread.CurrentThread.ManagedThreadId;
                 double total = calisan.SaatlikUcret * calisan.ToplamCalisma;
                 Console.WriteLine("İşlem {0} nolu thread tarafından gerçekleştirildi.\n
                 {1} numaralı çalışanın alacağı toplam ücret:{2}\n",threadid,calisan.ID,total);
            });
}
Çıkan sonuçlara baktığımızda hemen hemen herbir çalışanın toplam alacağı ücret farklı bir thread üzerinden hesaplandığını görmekteyiz. Tabi her çalıştırdığımızda farklı bir sonuç görmemiz normal bir durumdur. Bazen tek bir thread id'ye sahip olan bir thread üzerinden de işlemler yapılabilir. Yazımızın sonuna gelirken kısaca bir özetlersek basit olarak for ve foreach döngülerini Task Parallel Library kullanarak nasıl parallelleştirebiliriz bu konu üzerinde durduk ve birkaç basit örnek yaptık. İlerleyen yazılarda da daha kompleks senaryolar üzerinde duracağız ve döngülerin paralelleştirilmesini daha da detaylı bir şekilde inceleyeceğiz. Şimdilik bu kadar, Görüşmek Üzere,


Yorum Gönder


Yorumlar

  • profile

    Cihangir Geveci

    • 2
    • 11
    • 2012

    Çok Açıklayıcı ve anlaşılır olmuş, eline sağlık...