wtorek, 12 listopada 2013

StringBuilder pokazuje swoją moc wtedy gdy przy użyciu String.Concat tworzonych jest bardzo wiele tymczasowych obiektów, które łączone są w jeden cały tekst. StringBuilder posiada wewnętrzny bufor, który eliminuje konieczność tworzenia i niszczenia przez GC bardzo wielu obiektów.

Gdy piszemy:
for(int i = 0; i < 100; i++)
   text += text + i;

w każdym obiegu pętli tworzymy trzy tymczasowe obiekty, których kreacja zajmuje niezerowy czas. Do tego dochodzi jeszcze praca GC, który musi zająć się tymi wszystkimi tymczasowymi obiektami.

Dużo lepiej jest napisać:
var sb = new StringBuilder("");
for (int i = 0;  i < 100;  i++)
{ 
   sb.Append("test"); 
   sb.Append(i);
}

W swoim przykładzie (POBIERZ TUTAJ) zmierzyłem czas wykonania metod, w których tworzę tekst zawierający kolejne wartości Ciągu Fibonacci'iego. Poniżej znajdują się wynik pomiaru czasu wykonania dla dziewięćdziesięcio-elementowego ciągu:

Gdy StringBuilder szybszy od String.Concat

Dalsze zwiększenie liczby elementów ma mały sens ponieważ wartości ciągu nie mieszczą się w obiekcie Int64. Jednak już przy niedużej liczbie obiegów pętli, równej dziewięćdziesiąt, różnica w prędkości wykonania tych metod jest znacząca. StringBuilder jest około sześć razy szybszy.

P.S. Czas tworzenia tekstu zawierającego kolejne elementy ciągu nie jest zależny od sposobu obliczenia tego ciągu. Kolejne wartości Ciągu Fibonacci'ego wcześniej obliczyłem i zapisałem w tablicy do której sięgam tylko i wyłącznie w celu odczytu. Czas tworzenie tekstu z ciągiem również  nie jest zależny od czasu wyświetlania tego tekstu na ekranie.

Ciekawostka.
W .NET 4.0 oraz 4.5 wewnętrzna implementacja obiektu StringBuilder oparta jest o listę jednokierunkową. Wcześniej była to tablica. Skutek: teraz ustawienie własności Lenght na zero powoduje spadek wydajności. Linki o tym mówiące: 
Po za tematem.
Obliczanie Ciągu Fibonnaciego w sposób rekurencyjny jest nie do opisania wolniejszy od sposobu bazującego na tymczasowej tablicy wyników. Pomiary czasu tych implementacji nie należą do treści tego posta, do których zachęcam już w własnym zakresie.

Sposób rekurencyjny:
public static int Fibonacci(int n)
{
   if (n == 0) return 0;   
   if (n <= 2)  return 1;
   return Fibonacci(n - 2) + Fibonacci(n - 1);
}

Sposób z tymczasową tablicą wyników:
public static int Fibbonacci(int n)
{
   int[] fibo = new int[100];
   fibo[0] = 0;
   fibo[1] = 1;
   fibo[2] = 1;

   if (n <= 2)  return fibo[n];

   for (int i = 3; i < n+1; i++)
      fibo[i] = fibo[i - 2] + fibo[i - 1];

   return fibo[n];
}

0 komentarze :

Prześlij komentarz