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 sayilar = Enumerable.Range(1, 1000000).ToList();
 
// foreach döngüsü
var swForeach = new Stopwatch();
swForeach.Start();
try
{
    foreach (int i in sayilar)    {
        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 < sayilar.Count; i++)    {
        int j = sayilar[i];<br />    }
}
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 metodlar çağırılmaktadır. Bu durum foreach döngüsünün daha yavaş çalışmasına sebep olmaktadır.

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.

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.

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.

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.