C++ PERFORMANS İPUÇLARI

C++ Performans ipuçları

Bir çok yerde c++ için performans iuçları bulunabilir ama ben bu yazımda daha pratik bir örnek üzerinden gitmekistiyorum yani önce hayali bir senaryo için bir fonksiyon yazmanızı isteyeceğim (aslında ben yazacağım tamam ama en genel ilk akla gelen şeklinde yazacağım) daha sonra burada ne gibi performans iyileşirmeleri yapabiliriz sıra ile gideceğiz.

1. VERILENLER

Aşağıdaki gibi bir işçi (Employee) sınıfımız var diyelim;

    class Employee {
     string addr;
    }

2. İSTENILENLER

Şimdi sizden bir fonksiyon yazmanızı; bu fonksiyonun verilen bir liste içinde herhangi bir ada ait employee nesnesinin adres bilgisini döndürmenizi istesek ???

herhalde çoğunuz aşağıdaki gibi birşey düşünmüş veya yazmıştır.

      string FindAddr( list l, string name )
      {
        for( list::iterator i = l.begin();
             i != l.end();
             i++ )
        {
          if( *i == name )
          {
            return (*i).addr;
          }
        }
        return "";
      }

Şimdi buradaki hataları aşağıdaki gibi sıralayalım

    1. Öncelikle pass by value ile parametre olarak geçireceğiniz değişkenler için const& (referans) kullanamaya özen gösterin; çünkü pass by value işlemi listeyi ve stringi kopyalamaya çalışır. Aksi takdirde şu anda parametre olarak geçtiğiniz yüzbinlik employee listesi tüm elemanları ve değişkenleri ile tek tek kopyalandı. Eğer değişiklik yapmayacaksanız geçtiğiniz parametlere const eklemeyi alışkanlık haline getirin.
    1. i++ (postincrement) yerine ++i (preincrement) kullanın; çünkü i++ işleminde i değerini bir arttırıp eski değerini geçici bir değişken yaratarak geri dönderir. Bu küçük bir ipucu fakat milyonlarca döngü yapıyorsanız biraz zaman kurtarabilirsiniz;
    1. Bazılarınızın aklına takılmıştır, *i == name işleminin geçerli olması için Employee sınıfının ya stringe çevrilir olması ya da string alan bir çevirici constructora(kurucu fonksiyona) sahip olması gerekir. Her iki durumda da =operatörünü çağıran geçici birer nesne yaratılır. Geçici nesne yaratılmamasının tek yolu bir =operatörünün tanımlanmış olmasıdır.
class Employee {
   string addr;
   Employee operator=(const Employee& other);//Gerçekleştirmeyi unutmayın
   }
    1. Gelelim son satıra, return “” gibi bir değer döndürmektense yerel bir değişken tanımlayıp bunu döndürmek daha iyidir. Derleyicinin sizden gizli değişken yaratma işlemlerine dikkat edin, bunun önüne geçmenin bir yolu constructorlarınızı explicit yapmak olabilir. Bir fonksiyonda sadece tek bir return ifadesi kullanmaya çalışın. Bu durum derleyicinin yerel değişkenleri devre dışı bırakacak return value optimizasyonu yapmasını sağlar, yani aşağıdaki kod bloğu yazıldığında derleyici a değeri için optimizasyon yapabilir.
string a = FindAddr( l, "Harold" );
  1. Burada string yerine string&(yani bir string referansı) döndürmek geçici değişken yaratmamak için çözüm gibi görünebilir ama fonksiyondan çıkılır çıkılmaz yerel değişkenin geçerliliği biteceği için döndürdüğünüz değer asla geçerli olmayacak ve programınız hiç ummadığınız davranışlar sergileyecektir. Yani asla ama asla yerel değişkenlere referans döndürmeyin! Toparlayacak olursak doğru şekli:
   string FindAddr( const list& l, const string& name )
  {
    string addr;
    for( list::const_iterator i = l.begin();
         i != l.end();
         ++i )
    {
      if( (*i).name == name )
      {
        addr = (*i).addr;
        break;
      }
    }
    return addr;
  }

Şimdi gelelim başka optimizasyon işlemlerine, aşağıdaki kod bloğunu inceleyelim

   for( int i = 0; i < numPixels; i++ )
	{
   		rendering_context->back_buffer->surface->bits[i] = some_value; 
	}

Öncelikle döngünün her aşamasında yapılan pointer-indirection işlemi mutlaka çok zaman harcamaktadır, bunun için bu ifadeyi bir defalık döngünün dışında asıl işaret edilmek istenen değere bir pointer atamak tüm derefarans işlemini her defasında yapmaya göre işimizi bayağı hızlandıracaktır:

unsigned char *back_surface_bits = rendering_context->back_buffer->surface->bits;
for( int i = 0; i  < numPixels; i++ )
{
   back_surface_bits[i] = some_value;
}

yukarıdaki optimizasyonu birkaç adım daha ileri taşımak için; pre-increment tercih ediyor ve pointerı index ile değil arttırma ile kullanıyoruz:

unsigned char *back_surface_bits = rendering_context->back_buffer->surface->bits;
for( int i = 0; i < numPixels; ++i, ++back_surface_bits )
{
   *back_surface_bits = some_value;
}

Bugünlük bukadar gençler, hemen dağılmayın bir dakika. Eğer sizin de bildiğiniz birkaç şey var ise yorumlarınızda paylaşın böylece burası daha faydalı ve hatırlamak istediğimizde dönüp bakabileceğimiz bir yer olarak kalsın. 🙂

Reklamlar

Bir Cevap Yazın

Aşağıya bilgilerinizi girin veya oturum açmak için bir simgeye tıklayın:

WordPress.com Logosu

WordPress.com hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap / Değiştir )

Twitter resmi

Twitter hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap / Değiştir )

Facebook fotoğrafı

Facebook hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap / Değiştir )

Google+ fotoğrafı

Google+ hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap / Değiştir )

Connecting to %s