Şimdi Ara

C# Performans Arttırma – Döngüler

Daha Fazla
Bu Konudaki Kullanıcılar: Daha Az
2 Misafir - 2 Masaüstü
5 sn
5
Cevap
0
Favori
890
Tıklama
Daha Fazla
İstatistik
  • Konu İstatistikleri Yükleniyor
0 oy
Öne Çıkar
Sayfa: 1
Giriş
Mesaj
  • Orijinal makale: C# Performans Arttırma – Döngüler C# Performans Arttırma – Döngüler


    Foreach yerine for döngüsü kullanmayı düşünün

    Foreach döngüsü hayatımızı kolaylaştırsa da bazı istisnalar dışında for döngüsü daha iyi performans göstermektedir. Bu durumu aşağıdaki kodu inceleyerek açıklamaya çalışalım.
    Performans ölçümü için System.Diagnostics.Stopwatch sınıfı kullanılmıştır.

    var sayılar = Enumerable.Range(1, 1000000).ToList(); 

    // foreach döngüsü
    var swForeach = new Stopwatch();
    swForeach.Start();
    try
    {
    foreach (int i in sayılar)
    {
    int j = i;
    }
    }
    finally
    {
    swForeach.Stop();
    }
    Console.WriteLine("Süre: {0}", swForeach.Elapsed);
    // Süre: 00:00:00.0287938


    // for döngüsü
    var swFor = new Stopwatch();
    swFor.Start();
    try
    {
    for (int i = 0; i < sayılar.Count; i++)
    {
    int j = sayılar[i];
    }
    }
    finally
    {
    swFor.Stop();
    }
    Console.WriteLine("Süre: {0}", swFor.Elapsed);
    // Süre: 00:00:00.0090397


    Testler sonucunda for döngüsünün 3 kat daha hızlı tamamlandığı görülmektedir. Peki buna sebep olan nedir? Neden for döngüsü daha hızlı çalışmaktadır? Buna sebep olan derleyicinin foreach döngüsü için arka planda enumerator object kullanmasıdır. Derleyici tarafından foreach döngüsü için oluşturulan IL çıktısı aşağıdadır; Çıktıda kolayca fark edebileceğiniz üzere her bir döngüde sayılar listesinin Enumerator sınıfındaki metotlar çağrılmaktadır. Bu durum foreach döngüsünün daha yavaş çalışmasına sebep olmaktadır.

    IL_001E:  callvirt    System.Collections.Generic.List.GetEnumerator 
    IL_0023: stloc.s 05
    IL_0025: br.s IL_002F
    IL_0027: ldloca.s 05
    IL_0029: call System.Collections.Generic.List.get_Current
    IL_002E: stloc.2
    IL_002F: ldloca.s 05
    IL_0031: call System.Collections.Generic.List.MoveNext
    IL_0036: brtrue.s IL_0027
    IL_0038: leave.s IL_0048
    IL_003A: ldloca.s 05
    IL_003C: constrained. System.Collections.Generic.List<>.Enumerator


    Koleksiyonlar üzerinde inline döngülerden kaçının
    Teknik olarak aşağıdaki iki kodunda aynı sonucu vereceğini ve arada bir hız farkı olmayacağını düşünebilirsiniz. Eğer böyle düşünüyorsanız aradaki farkı görünce fikriniz değişecektir.

    // Kullanın 
    List sayılar = Enumerable.Range(1, 1000000).ToList();
    foreach (int item in sayılar)
    {
    var j = item;
    }
    //Süre: 00:00:00.0028942


    // Kaçının
    foreach (int item in Enumerable.Range(1, 1000000).ToList())
    {
    var j = item;
    }
    //Süre: 00:00:00.0136188


    Test sonuçlarında lokal değişken olarak tanımlanmış koleksiyon ile döngü içerisinde inline olarak kullanılan koleksiyon arasındaki hız farkı bariz bir şekilde görülmektedir. Bu durum bir önceki örnekte bahsedilen Enumerator çağırma ile bağlantılıdır ve kaçınılması gerekir.

    Gerektiğinde paralel döngüleri tercih edin
    Eğer döngü içerisinde yoğun işlemci gücü gerektiren kodlar çalıştırıyorsanız paralel döngüler performans artışı sağlayabilir. Bu döngüler standart döngüler gibi sıralı değil paralel olarak çalışmaktadır. Bu sayede işlemci gücü maksimum oranda kullanılır.

    var anahtarlarPF = new string[600]; 
    Parallel.For(0, anahtarlarPF.Length, i => anahtarlarPF[i] = RSA.Create().ToXmlString(true));
    // Süre: 00:00:07.3489338

    var anahtarlarF = new string[600];
    for (int i = 0; i < anahtarlarF.Length; i++)
    {
    anahtarlarF[i] = RSA.Create().ToXmlString(true);
    }
    // Süre: 00:00:28.7663622


    ToString() metodunu dikkatli kullanın
    Özellikle döngüler içerisinde gereksiz tür değişimleri yapmayın. String türündeki bir değeri tekrar stringe dönüştürmek bedava değildir ve aşağıdaki örnekte olduğu gibi 40 kat daha yavaş çalışabilir.
    private static Random fRandom = new Random(); 

    private void Test()
    {
    string metin = string.Empty;
    for (int i = 0; i < 10000; i++)
    {
    int num = fRandom.Next(0, 26);
    metin += (char)('a' + num) + " ";
    }

    Stopwatch sp1 = new Stopwatch();
    sp1.Start();
    try
    {
    int boşluklar1 = 0;
    for (int i = 0; i < metin.Length; i++)
    {
    if (metin[i] == ' ') // DOĞRU :)
    {
    boşluklar1++;
    }
    }
    }
    finally
    {
    sp1.Stop();
    }
    Console.WriteLine("Süre: {0}", sp1.Elapsed);
    // Süre: 00:00:00.0000141

    Stopwatch sp2 = new Stopwatch();
    sp2.Start();
    try
    {
    int boşluklar2 = 0;
    for (int i = 0; i < metin.Length; i++)
    {
    if (metin[i].ToString() == " ") // YANLIŞ :(
    {
    boşluklar2++;
    }
    }
    }
    finally
    {
    sp2.Stop();
    }
    Console.WriteLine("Süre: {0}", sp2.Elapsed);
    //Süre: 00:00:00.0005905
    }


    Diğer öneriler
    For döngülerini tersine (azalan) şekilde çalıştırmak X86 tabanlı bazı işlemcilerde performans artışı sağlayabilir.
     for (int i = metin.Length - 1; i >= 0; i--) 

    Eğer döngüde işiniz bittiyse döngüden çıkın.
    List meyveler = new List(new string[] { "elma", "armut", "kiraz" }); 
    int index = -1;
    for (int i = 0; i < meyveler.Count; i++)
    {
    if (meyveler[i] == "kiraz")
    {
    index = i;
    break; // Çıkın
    }
    }[b][/b]







  • Paylaşım için teşekkürler. Çoğu zaman göz ardı edilen, püf noktaları.

    < Bu ileti tablet sürüm kullanılarak atıldı >
  • artık günümüz bilgisayarları ve configürasyon ları için sorun olmaz ama web tarafında sorun olabilir
  • Teşekkürler okumaya değer.
  • Faydalı bir yazı herkes tarafından bilinmesine rağmen dikkat edilmeyen unutulan gerçekler ama kullanılabilirlik açısından yararsız bi makale.

    Projendeki tüm foreach'leri for yapsan değişen ne olacak? 1 milyonluk bi döngüde bile fark neredeyse yok. Görünürde 3 kat olsa da yok yani. 0.0000000000000000001 gibi bi rakam kimseye birşey katmaz. Kaldı ki gerçek hayatta kullanılan foreach'ler click başı ortalama 10-100-1000 arası gidip geliyor.

    Günümüzde bu taktiklerin bir önemi kalmıyor malesef. Performans artık %99.9 database performansı. Konu performans olacaksa database sorgularını nasıl optimize edebiliriz, nasıl cache kullanırız vs. olmalı.

    Zaten bunlar önemli olsa herkes dikkat edip projede foreach'leri for yapardı vs. Boş yere bunlar için kastırmaya gerek yok.
  • Yapay Zeka’dan İlgili Konular
    Daha Fazla Göster
    
Sayfa: 1
- x
Bildirim
mesajınız kopyalandı (ctrl+v) yapıştırmak istediğiniz yere yapıştırabilirsiniz.