Projelerimizde en çok kullandığımız değişken tipi string olsa gerek. String tipinin reference type ve immutuable olması, projelerde hayli yer alması bizim string değişkenlerle yaptığımız işlemlerde performansa ne kadar dikkat etmemiz gerektiğini gösteriyor.  String immutuable bir değişken tipidir, dedik. Bunun anlamı string bir değişkene verdiğimiz değeri (aslında değerin adresini) asla değiştiremeyiz. Bunu basit bir örnekle açıklamaya çalışalım.            

string test = “Veri”;

//Bir takım işler

test = “Data”;

Burada yaptığımız heap’de bir yer ayırıp içine “veri”yi koymaktan ve bu yerin adresini test değişkenine vermekten başka bir şey değil. Daha sonra yapılan ise heap’de bir yer daha ayırıp içine “data”yı koymak ve test değişkenine “data”nın adresini vermek. Yani heap’de aslında iki tane yerimiz var (biri “veri”yi içeriyor diğeri “data”yi) ama test değişkenimiz sadece “data”nın bulunduğu adresi tutuyor. Bu şekilde düşündüğümüzde string üzerinde yaptığımız her yeni atamada aslında içindeki veriyi değil, adresini değiştirmiş oluyoruz ve hafızada (heap’de) belki de farkında olmadan fazladan yer tutuyoruz; ta ki garbage collector (GC) zamanı gelip de “veri” nin adresini tutan herhangi bir değişken bulamayıp temizlediği zamana kadar…  Şimdi de bir karşılaştırma örneğine bakalım. 

string test1 = “veri”;

string test2 = “data”; 

 // Bir takım işlemler 

if (test1.ToUpper() == test2.ToUpper())  

 {      // Bir takım işlemler   }

    Proje çıktısının ilgili yerini ILDASM ile inceleyelim:    

string3.jpg


Görüyoruz ki hafızada test1.ToUpper()’ın sonucu başka bir yerde, test2.ToUpper()’ın sonucu başka bir yerde tanımlanıp farklı değişkenlere alınıyor. (Heap’de “veri”, “data”, “VERİ”, “DATA”  yerleri mevcut ve stackda “VERİ”’nin ve “DATA”nın adresini tutan iki ayrı değişken tanımlanmış) Daha sonra da boolean bir değişken tanımlanıp string fonksiyonlarından Equality kullanılarak karşılaştırıldığını görüyoruz. Peki if bloğunu şu şekilde değiştirirsek ne olur acaba, bakalım:  

if (string.Compare(test1,test2,true) == 0)

   {      // Bir takım işlemler   }

  ILDASM ile proje çıktısının ilgili satırına bakarsak:   

string2.jpg

Fazladan hafızada yer ayırmalar ve değişken tanımlamalar olmamış. Bu da kodumuzun öncekine göre daha performanslı olmasına ve daha az hafıza kullanılmasına sebep olmuştur. String işlemlerinde sıkça kullandığımız bir başka işlem de birleştirmelerdir. Basit bir örnekle bunu da analiz etmeye çalışalım.  

string test = “veri1″;

//Bir takım işlemler 

test += ” veri2″;  

//Bir takım işlemler 

test += ” veri3″;

     

string3.jpg

ILDASM çıktısına ve önceki bilgilerimize göre ilk string birleştirmede aslında heapde bir yer ayrılıp içine “veri1 veri2” yazıldığını ve bunun adresini bizim değişkenimizin tuttuğunu görürüz. Benzer şekilde ikinci birleştirme de heap’de “veri1 veri2 veri3” yazan bir yer ayrıldığını ve bunun adresini değişkenimizin tuttuğunu rahatlıkla söyleyebiliriz. (Heap görüntüsü şöyledir: “veri”, veri1 veri2, “veri1 veri2 veri3” Yani hafızada 3 ayrı yer ayrılmıştır.)  Yani string değişkenimizin içeriğini aslında değiştiremiyoruz, çünkü kendisi immutuable’dır… Bu duruma alternatif çözüm StringBuilder sınıfı ile gelmektedir:   

StringBuilder sb = new StringBuilder();

sb.Append(“veri1″);           

 //Bir takım işlemler 

sb.Append(“veri2″); 

//Bir takım işlemler  sb.Append(“veri3″);

     

Aslında her zaman StringBuilder sınıfını kullanmak istenen performansı vermeyecektir. Bu sebeple String birleştirme işlemi belirli bir sayıda ise + veya concat metodunu kullanmak daha faydalı iken, belirsiz ve fazla sayıda string birleştirmeler de StringBuilder sınıfını kullanmak daha iyi olacaktır. Bu tavsiyeyi MSDN’de de görüyoruz:

“The String class is preferable for a concatenation operation if a fixed number of String objects are concatenated. In that case, the individual concatenation operations might even be combined into a single operation by the compiler. A StringBuilder object is preferable for a concatenation operation if an arbitrary number of strings are concatenated; for example, if a loop concatenates a random number of strings of user input.” 

Projelerimizin minimum kaynak tüketimi ile maksimum performansta çalışmalarını isteriz. Burada da buna nasıl katkı sağlayacağımızı birkaç string işlemi üzerinde incelemeye çalıştık. Belki onlarca satırdan kazanacağımız birkaç ms ve hafızadan tasarruf edebileceğimiz birkaç byte çok fazla bir fark ettirmeyecektir. Ancak unutulmamalıdır ki projelerdeki satır sayısı arttıkça ve yaptığımız işlemler daha da karmaşıklaştıkça bu tip küçük şeylerin aslında ne denli önemli olduğu ortaya çıkacaktır. Ayrıca .NET Framework mimarisinin nasıl çalıştığını anlamamıza bir o kadar da yardımcı olacaktır.  

One Response to “String İşlemlerinde Performans”

  1. BatuhanS says:

    Ergün Bey öncellikle makaleniz çok güzel ve yol gösterici fakat .NET ortamında yazılım geliştirmek için geç kalmış olan ben Aşağıdaki şekilde bir uygulama yazdım
    ******************************************
    Dim s, t, a, i, j, b, k, km As Object
    Dim kelime As Object
    Dim bul, top_Renamed, sec As Object
    Dim secili, sec1 As Object
    Dim listkelime, listkelime1 As Object

    For t = 1 To Len(Text1.Text)
    k = Mid(Text1.Text, 1, 1)
    Text1.Text = Replace(Text1.Text, k, “”)
    If InStr(1, kelime, k) = 0 Then
    kelime = kelime & k
    End If
    Next t
    Text1.Text = kelime
    For i = 0 To List1.Items.Count – 1
    List1.SelectedIndex = i
    top_Renamed = 0
    For j = 1 To Len(kelime)
    sec = Mid(kelime, j, 1)
    bul = InStr(1, List1.Text, sec)
    If bul > 0 Then
    secili = List1.Text
    For s = 1 To Len(kelime)
    sec1 = Mid(kelime, s, 1)
    secili = Replace(secili, sec1, “”)
    Next s
    If Len(secili) = 0 Then
    top_Renamed = top_Renamed + 1
    End If
    End If
    Next j
    listkelime = List1.Text
    For t = 1 To Len(List1.Text)
    k = Mid(List1.Text, t, 1)
    listkelime = Replace(listkelime, k, “”)
    If InStr(1, listkelime1, k) = 0 Then
    listkelime1 = listkelime1 & k
    End If
    Next t
    If top_Renamed = Len(listkelime1) Then
    List2.Items.Add(List1.Text)
    End If
    listkelime1 = Nothing
    Next i
    ****************************************

    Program text deki harflerden oluşan list1 item lerini list 2ye aktarıyor. list1de 65000 civarında kelime barındırdığı için bu işlem çok uzun ve çok zahmetli oluyor anladığım kadarı ile stringbuilder kullanarak bu performans düşüklüğünü gidereblirim şöyle bir ip ucu daha var ki list2 ye eklenecek kelimelerin max uzunluğu 8 karaketr.
    sizden istirhamım benim string builder kullanarak yapmaya çalışıpda başarılı olamadığum kod bloğunu string builder kullnılmış halini örneklemeniz, şimdiden teşekkürler

Leave a Reply