StringBuilder - czemu i kiedy używać

2012-02-03 14:00

Rejestracja: 12 lat temu

Ostatnio: 2 lata temu

0

Słyszałem że warto używać tej klasy zamist stringa gdy będziemy robić operacje na danym tekście.
Ale kiedy warto stosować? Powyżej ilu operacji?
Bo niby to oszczędza pamięć jako że dodając do stringa tworzymy jego kopię.
Ale jak mamy taki program

 StringBuilder sb = new StringBuilder();
for (int i = 0 ; i < 100 ; i++)
{
sb.AppendLine("znak " + i); //tu za każdym razem tworzymy string "znak" oraz string "znak" + i 
Console.Clear();
Console.WriteLine(sb.ToString()); //tu konwertujemy sb do stringa czyli tworzymy znowu obiekt typu string!
}

Oczywiście program nie ma żadnego znaczenia, chciałem tylko pokazać o co mi chodzi. Zdaje mi się że podczas operacji na StringBuilderze tworzymy i tak masę niepotrzebnych stringów. Potem pokazując zawartość SB'ka znowu tworzymy obiekt typu string. Przecież to istny bałagan. Nie mniejszy chyba niż ze string += dane.
Czy mógłby mi ktoś wytłumaczyć kiedy i dlaczego i jak warto używać SB'ka?

Pozostało 580 znaków

2012-02-03 14:13

Rejestracja: 16 lat temu

Ostatnio: 21 godzin temu

0

Ale kiedy warto stosować? Powyżej ilu operacji?
kiedyś czytałem że powyżej czterech, a to było na blogu pracownika Microsoftu, który zajmował się .netem.
Możesz zrobić mały benchmark, zmierzyć która klasa działa szybciej w danym przypadku.

Generalnie jest tak, że StringBuilder powinien być zawsze szybszy, gdyż nie tworzy całkiem nowego stringa przy każdej operacji. Jednak kompilator traktuje typ String specjalnie, i stosuje dla niego specjalne optymalizacje (a dla StringBuildera nie).

W przykładzie który podałeś, SB jest jak najbardziej uzasadniony. W przykładzie typu:

string s = "ala ma " + n.ToString() + " kotów"

lepiej zostawić po prostu string.

edytowany 1x, ostatnio: Azarien, 2012-02-03 14:14

Pozostało 580 znaków

msm
2012-02-03 14:34
msm
Administrator

Rejestracja: 11 lat temu

Ostatnio: 2 tygodnie temu

0

Generalnie jest tak, że StringBuilder powinien być zawsze szybszy, gdyż nie tworzy całkiem nowego stringa przy każdej operacji. Jednak kompilator traktuje typ String specjalnie, i stosuje dla niego specjalne optymalizacje (a dla StringBuildera nie).

Nie do końca, StringBuilder alokuje sobie po prostu nadmiarowy bufor żeby móc szybko do niego dopisywać. StringBuilder ma (wg. panów z Microsoftu) specjalne traktowanie i nie da się napisać swojej klasy działającej równie szybko.

W przykładzie który podałeś, StringBuilder jest jak najbardziej uzasadniony. W przykładzie typu:

string s = "ala ma " + n.ToString() + " kotów"

lepiej napisać

string s = string.Format("ala ma {0} kotów", n)" // :P

ale to już nie dla wydajności tylko dla pięknego kodu.

Ja czytałem że warto stosować od około ośmiu operacji. Ale to wszystko zależy od wielkości łączonych stringów etc, etc, etc. Należy się bawić z tym dopiero wtedy kiedy ma to znaczący wpływ na wydajność (na przykład generowanie długie tekstu, ale dodanie kilku stringów jednorazowo po tym jak użytkownik kliknie na przycisk oczywiście nie).

Pozostało 580 znaków

2012-02-03 15:10

Rejestracja: 9 lat temu

Ostatnio: 20 godzin temu

0

Tu jest dość ciekawy artykuł:
http://www.codeproject.com/Ar[...]ng-Fast-String-Operations-wit

Pozostało 580 znaków

bo
2012-02-03 15:32
bo
1

String w C# (i w Javie) jest immutable, każda zmian powoduje przepisanie w nowe miejsce.
W Javie kod

        StringBuilder zwrot=new StringBuilder("");
        for (int i=1;i<=300000;i++)
        {
            zwrot.append("A");
        }

jest ponad 32 tysiące razy szybszy niż kod

        String zwrot="";
        for (int i=1;i<=300000;i++)
        {
            zwrot+="A";
        }

Pozostało 580 znaków

2012-02-03 15:55

Rejestracja: 9 lat temu

Ostatnio: 6 lat temu

0

Słusznie zauważyłeś, że w twoim przykładzie i tak tworzysz 100 nowych stringów, dlatego nie powinieneś tam używać konkatenacji stringów, ale wszystko appendować:

sb.Append("znak ").Append(i).AppendLine();

W przypadku Javy, w wielu IDE można włączyć, by zwykła konkatenacja wewnątrz append() powodowała ostrzeżenie.

I wcale nie jest tak, że za każdym razem tworzysz stringa "znak " - jest on przechowywany w puli stringów i za każdym razem odwołujesz się do tego samego obiektu.

edytowany 2x, ostatnio: iooi, 2012-02-03 15:57

Pozostało 580 znaków

2012-02-03 15:56

Rejestracja: 12 lat temu

Ostatnio: 2 lata temu

0

Szybkość szybkością a jak z pamięcią? Czy da się jakoś usuwać starą kopię stringa przy operacji
string zwrot = "";
zwrot += "dupa";
Czy w ogóle typy referencyjne da się jakoś usuwać? Wiem że jest interfejs IDisposable ale jak powinien w takim razie wyglądać kod zwalniający pamięć w funkcji Dispose?

Pozostało 580 znaków

Rev
2012-02-03 16:02
Rev
Moderator

Rejestracja: 13 lat temu

Ostatnio: 1 dzień temu

0

Interfejs IDisposable służy do usuwania obiektów z pamięci niezarządzanej oraz zwalniania niezarządzanych uchwytów.

O czymś takim jak Garbage Collector słyszałeś?


Pozostało 580 znaków

2012-02-03 16:19

Rejestracja: 12 lat temu

Ostatnio: 2 lata temu

0

A czy takie wyrażenie

Console.WriteLine("tekst {0}", a);

jest lepsze aniżeli

Console.WriteLine("tekst " + a);

I czy wyrażenie

StringBuilder esbek = new StringBuilder(); 
double d = 123.3;
esbek.Append(d.ToString());

jest identyczne co

StringBuilder esbek = new StringBuilder(); 
double d = 123.3;
esbek.Append(d);

Nie pytam oczywiście o kwestie estetyczne

edytowany 1x, ostatnio: ubuntuser, 2012-02-03 16:19
No chyba skoro przy 2 przykładzie nie wywala ostrzeżenia o niejawnym konwertowaniu double na stringa to robi to automatycznie więc wychodzi na to samo tylko 2 przykład mniej do pisania ;d - nerf 2012-02-03 16:39

Pozostało 580 znaków

2012-02-05 16:57

Rejestracja: 12 lat temu

Ostatnio: 2 lata temu

0

Mam ważne pytanie.
Piszę sobię w międzyczasie aplikację ala telnet. No i produkuje ona ogromne ilości tekstu, po połączeniu np z serwerem IRC.
Korzystam z kontrolki RichTextBox, której tekst jak wiadomo można dodać za pomocą richTextBox.Text += tekst.
Pewnie nie jest to słuszne rozwiązanie? Jak mógłbym to inaczej zrobić? Tak czy siak wiadomość musi wyjść na ekran, w czasie niezbyt późnym od jej dostania. Co proponujecie? Z góry dzięki za pomoc

dobra dobra, ale kwestia szybkosci to inna sprawa. ja na bieżąco po dostaniu nowej linii ze streamreadera je wpisuje. więc one się pojawiają wtedy kiedy trzeba. a chodzi ogolnie o rozwiazanie richtextbox.Text += tekst czyli generacji za kazdym razem nowego stringa. nawet jak dam StringBuilder to i tak bede musial za kazdym razem zrobic richtextbox.Text = stringbuilder.ToString() - ubuntuser 2012-02-05 17:26

Pozostało 580 znaków

2012-02-05 18:29

Rejestracja: 10 lat temu

Ostatnio: 5 lat temu

0

richTextBox1.AppendText("");

Pozostało 580 znaków

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0