it-swarm-tr.com

String vs. StringBuilder

String ve StringBuilder (StringBuilder değişken olabilir) arasındaki farkı anlıyorum, ancak ikisi arasında büyük bir performans farkı var mı?

Üzerinde çalıştığım programın birçok büyük harf dizgisi eki var (500+). StringBuilder kullanmak daha iyi bir seçim mi?

204
Kuvo

Evet, performans farkı önemlidir. KB makalesine bakın " Visual C # 'da dize bitiştirme performansı nasıl geliştirilir ".

Her zaman önce netliği kodlamayı denedim, sonra performans için daha sonra optimize ettim. Diğer yoldan yapmaktan çok daha kolay! Ancak, ikisi arasındaki uygulamalarımdaki büyük performans farkını gördükten sonra, şimdi biraz daha dikkatlice düşünüyorum.

Neyse ki, zamanınızı nereye harcadığınızı görmek için kodunuzda performans analizi yapmak ve daha sonra gerektiğinde StringBuilder kullanacak şekilde değiştirmek için nispeten kolay.

225
Jay Bazuzi

Eğer böyle bir şey varsa, Gillian'ın 4 string hakkında söylediklerini netleştirmek için:

string a,b,c,d;
 a = b + c + d;

o zaman dizeleri ve artı operatörünü kullanarak daha hızlı olur. Bunun nedeni (Java gibi, Eric'in işaret ettiği gibi), dahili olarak StringBuilder'ı otomatik olarak kullanıyor (Aslında, StringBuilder'ın da kullandığı ilkel bir özelliği kullanıyor)

Ancak, yaptığınız şeye yakınsa:

string a,b,c,d;
 a = a + b;
 a = a + c;
 a = a + d;

O zaman açıkça bir StringBuilder kullanmalısın. Net burada otomatik olarak bir StringBuilder oluşturmaz, çünkü anlamsız olacaktır. Her satırın sonunda, "a" (değişmez) bir dize olmalı, bu yüzden her satırda bir StringBuilder oluşturmak ve elden çıkarmak zorunda kalacaktı. Hız için, inşaatı bitirene kadar aynı StringBuilder'ı kullanmanız gerekir:

string a,b,c,d;
StringBuilder e = new StringBuilder();
 e.Append(b);
 e.Append(c);
 e.Append(d);
 a = e.ToString();
54
James Curran

StringBuilder tercih edilir _ eğer _ ise çoklu döngüler yapıyorsunuz veya kodunuzda çatallar var ... ancak PURE performansı için bir _ _ string bildirimi, o zaman bu çok daha başarılı.

Örneğin:

string myString = "Some stuff" + var1 + " more stuff"
                  + var2 + " other stuff" .... etc... etc...;

daha performans

StringBuilder sb = new StringBuilder();
sb.Append("Some Stuff");
sb.Append(var1);
sb.Append(" more stuff");
sb.Append(var2);
sb.Append("other stuff");
// etc.. etc.. etc..

Bu durumda, StringBuild daha sürdürülebilir olarak değerlendirilebilir, ancak tek string bildirisinden daha fazla performans göstermez.

10'dan 9 kez ... string oluşturucuyu kullan.

Bir yandan not: string + var aynı zamanda dahili olarak bir StringBuilder kullanan string.Format yaklaşımının (genellikle) reflektörden daha fazla performans gösterdiğine (şüpheliyken ... reflektörü kontrol et!)

28
calebjenkins

Bu kıyaslama, 3 veya daha az karakter dizisi birleştirildiğinde düzenli birleştirmenin daha hızlı olduğunu gösterir.

http://www.chinhdo.com/20070224/stringbuilder-is-not-always-faster/

StringBuilder, özellikle 500 karakter dizisi eklemeniz durumunda bellek kullanımında çok önemli bir gelişme sağlayabilir.

Aşağıdaki örneği düşünün:

string buffer = "The numbers are: ";
for( int i = 0; i < 5; i++)
{
    buffer += i.ToString();
}
return buffer;

Hafızada ne oluyor? Aşağıdaki dizeler oluşturulur:

1 - "The numbers are: "
2 - "0"
3 - "The numbers are: 0"
4 - "1"
5 - "The numbers are: 01"
6 - "2"
7 - "The numbers are: 012"
8 - "3"
9 - "The numbers are: 0123"
10 - "4"
11 - "The numbers are: 01234"
12 - "5"
13 - "The numbers are: 012345"

Bu beş sayıyı dizenin sonuna ekleyerek 13 dizge nesnesi yarattık! Ve 12 tanesi işe yaramazdı! Vaov!

StringBuilder bu sorunu giderir. .NET'te tüm dizelerin değişmez olduğunu ( sıkça duyduğumuzdan ("= --- --- ==)" değişken bir dize "değildir ). Dahili bir tamponu, bir karakter dizisi tutarak çalışır. Append () veya AppendLine () öğesini çağırmak, dizeyi char dizisinin sonundaki boş alana ekler; dizi çok küçükse, yeni, daha büyük bir dizi oluşturur ve buradaki tamponu kopyalar. Bu nedenle yukarıdaki örnekte, StringBuilder, arabelleğinin boyutuna bağlı olarak, dizeye 5 eklemenin tümünü içerecek tek bir diziye ihtiyaç duyabilir. StringBuilder'a tamponunun yapıcıda ne kadar büyük olması gerektiğini söyleyebilirsiniz.

23
Matt Trunnell

String birleştirme vs StringBuilder kullanırken hızdaki farkı göstermek için basit bir örnek:

System.Diagnostics.Stopwatch time = new Stopwatch();
string test = string.Empty;
time.Start();
for (int i = 0; i < 100000; i++)
{
    test += i;
}
time.Stop();
System.Console.WriteLine("Using String concatenation: " + time.ElapsedMilliseconds + " milliseconds");

Sonuç:

Dize birleştirmeyi kullanma: 15423 milisaniye

StringBuilder test1 = new StringBuilder();
time.Reset();
time.Start();
for (int i = 0; i < 100000; i++)
{
    test1.Append(i);
}
time.Stop();
System.Console.WriteLine("Using StringBuilder: " + time.ElapsedMilliseconds + " milliseconds");

Sonuç:

StringBuilder'ı kullanma: 10 milisaniye

Sonuç olarak, ilk yineleme 15423 ms iken, ikinci yineleme StringBuilder kullanarak 10 ms sürmüştür.

Bana öyle geliyor ki, StringBuilder kullanmanın daha hızlı, çok daha hızlı olduğunu düşünüyorum.

21
Diizzy

Evet, StringBuilder, bir dize üzerinde tekrarlanan işlem yaparken daha iyi performans sağlar. Tüm değişikliklerin tek bir durumda yapılması nedeniyle String gibi yeni bir örnek oluşturmak yerine çok zaman kazandırabilir.

String Vs Stringbuilder

  • String

    1. System namespace altında
    2. değişmez (salt okunur) örnek
    3. sürekli değer değişikliği gerçekleştiğinde performans düşer
    4. iş parçacığı güvenli
  • StringBuilder (değiştirilebilir dize)

    1. System.Text ad alanı altında
    2. değişebilir örnek
    3. mevcut durumda yeni değişiklikler yapıldığından daha iyi performans gösteriyor

Dotnet mob makalesini şiddetle tavsiye edin: C # ile String Vs StringBuilder .

İlgili Yığın Taşması sorusu: Dize C # 'da değişmediğinde dizenin değişkenliği? .

12
Shamseer K

StringBuilder, kullanılan fazladan hafıza pahasına, ayırma ve atama sayısını azaltır. Doğru kullanıldığında, derleyicinin, sonuç bulunana kadar daha büyük ve daha büyük dizeleri tekrar tekrar ayırma gereksinimini tamamen ortadan kaldırabilir.

string result = "";
for(int i = 0; i != N; ++i)
{
   result = result + i.ToString();   // allocates a new string, then assigns it to result, which gets repeated N times
}

vs.

String result;
StringBuilder sb = new StringBuilder(10000);   // create a buffer of 10k
for(int i = 0; i != N; ++i)
{
   sb.Append(i.ToString());          // fill the buffer, resizing if it overflows the buffer
}

result = sb.ToString();   // assigns once
8
moswald

String Vs String Builder:

Bilmeniz gereken ilk şey, bu iki sınıfın hangi Mecliste yaşadığını?

Yani,

string System namespace'de var.

ve

StringBuilder System.Text ad alanında bulunur.

string bildirgesi için:

System ad alanını dahil etmeniz gerekir. bunun gibi bir şey. Using System;

ve

StringBuilder bildirimi için:

System.text ad alanını dahil etmeniz gerekir. bunun gibi bir şey. Using System.text;

Şimdi asıl soruya gelin.

string & StringBuilder arasındaki fark nedir?

Bu ikisi arasındaki temel fark şudur:

dize değişken değil.

ve

StringBuilder değişkendir.

Yani şimdi değişmez ve değişken arasındaki farkı tartışalım.

Değişken: : Değiştirilebilir anlamına gelir.

Değiştirilemez: : Değiştirilemez anlamına gelir.

Örneğin:

using System;

namespace StringVsStrigBuilder
{
    class Program
    {
        static void Main(string[] args)
        {
            // String Example

            string name = "Rehan";
            name = name + "Shah";
            name = name + "RS";
            name = name + "---";
            name = name + "I love to write programs.";

            // Now when I run this program this output will be look like this.
            // output : "Rehan Shah RS --- I love to write programs."
        }
    }
}

Yani bu durumda aynı nesneyi 5 kez değiştireceğiz.

Yani bariz soru şudur! Aslında 5 kez aynı ipi değiştirdiğimizde, başlığın altında olan şey.

Bu aynı dizeyi 5 kez değiştirdiğimizde ne oldu?.

şekle bakalım.

enter image description here

Açıklama:

Bu değişkeni ilk defa "name" den "Rehan" i-e string name = "Rehan" için başlattığımızda, bu değişken "name" yığınında yaratılır ve bu "Rehan" değerine işaret edilir. Bu satırdan sonra: "name = name +" Shah ", referans değişkeni artık" Rehan "nesnesine işaret etmiyor, şimdi" Shah "işaret ediyor.

Dolayısıyla string değişmezdir, yani bellekte nesneyi yarattıktan sonra değiştiremeyeceğimiz anlamına gelir.

Böylece name değişkenini birleştirdiğimizde önceki nesne bellekte kalır ve başka bir yeni dize nesnesi yaratılır ...

Yani yukarıdaki şekilden beş nesneye sahibiz, dört nesne hiç kullanılmadıklarından atılıyor. Onlar hala bellekte kalırlar ve bellek miktarını bulurlar. "Çöp Toplayıcı" bundan o kadar temiz ki bu bellekten kaynaklanıyor.

Dize tekrar işlediğimizde herhangi bir zamanda dizgide tekrarlanan bazı nesneler vardır.

Demek Değişken dizgesinin hikayesi bu.

Şimdi StringBuilder Nesnesine bakalım. Örnek İçin:

using System;
using System.Text;

namespace StringVsStrigBuilder
{
    class Program
    {
        static void Main(string[] args)
        {
            // StringBuilder Example

            StringBuilder name = new StringBuilder();
            name.Append("Rehan");
            name.Append("Shah");
            name.Append("RS");
            name.Append("---");
            name.Append("I love to write programs.");


            // Now when I run this program this output will be look like this.
            // output : "Rehan Shah Rs --- I love to write programs."
        }
    }
}

Yani bu durumda aynı nesneyi 5 kez değiştireceğiz.

Yani bariz soru şudur! Aslında aynı StringBuilder'ı 5 kez değiştirdiğimizde, kaputun altında ne oldu.

Bu aynı StringBuilder'ı 5 kez değiştirdiğimizde gerçekleşen şeydir.

şekle bakalım. enter image description here

Açıklama: StringBuilder nesnesinin durumunda. yeni nesneyi elde edemezsin. Aynı nesne bellekteki değişim olacaktır, böylece nesneyi değiştirseniz bile 10.000 kez söylesek bile yine de yalnızca bir stringBuilder nesnesine sahip olacağız.

Çok fazla çöp nesnesi veya referansı olmayan stringBuilder nesnesi yok, çünkü neden değişebilir. Değişebilir bir anlamı var mı?

Farklılıkları:

  • Dize, System.Text ad alanında Stringbuilder olarak mevcut olduğu System ad alanında bulunur.
  • string, StringBuilder olarak mutabe olduğu durumlarda değişmezdir.
7
Rehan Shah

Bir String veya StringBuilder nesnesi için bir birleştirme işleminin performansı, bir bellek ayırmanın ne sıklıkla gerçekleştiğine bağlıdır. Bir String birleştirme işlemi her zaman bellek ayırır, ancak bir StringBuilder birleştirme işlemi yalnızca, StringBuilder nesne arabelleği yeni verileri barındıramayacak kadar küçükse belleği ayırır. Sonuç olarak, sabit sayıda String nesnesi birleştirildiğinde, bir birleştirme işlemi için String sınıfı tercih edilir. Bu durumda, bireysel birleştirme işlemleri, derleyici tarafından tek bir işlemde birleştirilebilir. İsteğe bağlı sayıda dizgi birleştirildiğinde bir birleştirme işlemi için bir StringBuilder nesnesi tercih edilir; örneğin, bir döngü rastgele sayıda kullanıcı girdisi dizesini birleştirirse.

Kaynak: MSDN

4
user487069

StringBuilder birçok sabit olmayan değerden bir dize oluşturmak için daha iyidir.

Bir HTML veya XML belgesindeki birden fazla değer satırı veya diğer metin parçaları gibi çok sayıda sabit değerden bir dize oluşturuyorsanız, hemen hemen tüm derleyicilerin yaptığı gibi "sürekli katlama", bir sürü sabit manipülasyona sahip olduğunuzda ayrıştırma ağacını azaltma işlemi (int minutesPerYear = 24 * 365 * 60 gibi bir şey yazdığınızda da kullanılır). Ve sabit değerlerin birbirine eklenmemiş olduğu basit durumlar için, .NET derleyicisi kodunuzu StringBuilder'in yaptığı gibi bir şeye düşürür.

Ancak ekiniz derleyici tarafından daha basit bir şeye indirgenemediğinde, bir StringBuilder isteyeceksiniz. Fizch'in işaret ettiği gibi, bu bir döngünün içinde gerçekleşmesi daha olasıdır.

3
JasonTrue
2
Jim G.

Birleştirme için dizeleri kullanmak, O(n^2) sırasındaki çalışma zamanı karmaşıklığına neden olabilir.

Bir StringBuilder kullanıyorsanız, yapılması gereken çok daha az bellek kopyası var. StringBuilder(int capacity) ile, final String in ne kadar büyük olacağını tahmin ederseniz performansı artırabilirsiniz. Kesin olmasanız bile, muhtemelen sadece birkaç kez StringBuilder kapasitesini artırmak zorunda kalacaksınız.

2
Steve g

Herhangi bir dize depolama için kullanmadan önce StringBuilder örneğinde EnsureCapacity(int capacity) yöntem çağrısını kullanmanın önemli performans kazancı olduğunu gördüm. Ben genellikle başlattıktan sonra kod satırına çağırırım. Bunun gibi StringBuilder örneğini başlattığınızdaki gibi aynı etkiye sahiptir:

var sb = new StringBuilder(int capacity);

Bu çağrı, önceden gereken gerekli belleği ayırır, bu da çoklu Append() işlemi sırasında daha az bellek tahsisine neden olur. Ne kadar belleğe ihtiyaç duyacağınıza dair bilinçli bir tahminde bulunmalısınız, ancak çoğu uygulama için bu çok zor olmamalıdır. Genellikle çok fazla hafızanın yanına bakarım (1k ya da öylesine konuşuyoruz).

2
Jason Jackson

StringBuilder'ın birlikte eklemeniz gereken 4'ten fazla dizginiz varsa daha hızlı olduğuna inanıyorum. Ayrıca AppendLine gibi harika şeyler de yapabilir.

2
Gilligan

.NET'te, StringBuilder hala dize eklemekten daha hızlıdır. Java'da dizeleri eklerken sadece başlık altında bir StringBuffer oluşturduklarından eminim, bu yüzden gerçekten bir fark yok. Bunu neden henüz .NET'te yapmadıklarından emin değilim.

2
Eric Z Beard

String ve StringBuilder aslında her ikisi de değişmezdir, StringBuilder, boyutunun daha verimli bir şekilde yönetilmesine izin veren arabelleklere sahiptir. StringBuilder'ın yeniden boyutlandırılması gerektiğinde, yığında yeniden tahsis edilen zamandır. Varsayılan olarak 16 karaktere kadardır, bunu yapıcıda ayarlayabilirsiniz.

örneğin.

StringBuilder sb = yeni StringBuilder (50);

1
capgpilk

Önceki cevaplara ek olarak, böyle konuları düşünürken daima ilk yaptığım şey küçük bir test uygulaması oluşturmaktır. Bu uygulama içinde, her iki senaryo için de bir zamanlama testi yapın ve daha hızlı olan kendiniz görün.

IMHO, 500'den fazla dize girişi eklemek kesinlikle StringBuilder'ı kullanmalı.

1
RichS

Dize bitiştirme size daha pahalıya mal olur. Java'da ihtiyaca bağlı olarak StringBuffer veya StringBuilder kullanabilirsiniz. Senkronize ve güvenli bir uygulama istiyorsanız, StringBuffer'a gidin. Bu, String birleştirme işleminden daha hızlı olacaktır.

Eşitlemeye veya Güvenli iş parçacığına ihtiyacınız yoksa, StringBuilder'a gidin. Bu, String birleştirme işleminden daha hızlı ve StringBuffer'den daha hızlı olacaktır;.

1
raffimd

StringBuilder önemli ölçüde daha etkilidir, ancak çok sayıda dize değişikliği yapmadığınız sürece bu performansı göremezsiniz.

Aşağıda performansın bir örneğini vermek için hızlı bir kod parçası verilmiştir. Görebildiğiniz gibi, gerçekten büyük yinelemeler yaptığınızda büyük bir performans artışı görmeye başlayabilirsiniz.

Gördüğünüz gibi 200.000 yineleme 22 saniye sürdü, StringBuilder kullanan 1 milyon yineleme neredeyse anında gerçekleşti.

string s = string.Empty;
StringBuilder sb = new StringBuilder();

Console.WriteLine("Beginning String + at " + DateTime.Now.ToString());

for (int i = 0; i <= 50000; i++)
{
    s = s + 'A';
}

Console.WriteLine("Finished String + at " + DateTime.Now.ToString());
Console.WriteLine();

Console.WriteLine("Beginning String + at " + DateTime.Now.ToString());

for (int i = 0; i <= 200000; i++)
{
    s = s + 'A';
}

Console.WriteLine("Finished String + at " + DateTime.Now.ToString());
Console.WriteLine();
Console.WriteLine("Beginning Sb append at " + DateTime.Now.ToString());

for (int i = 0; i <= 1000000; i++)
{
    sb.Append("A");
}
Console.WriteLine("Finished Sb append at " + DateTime.Now.ToString());

Console.ReadLine();

Yukarıdaki kodun sonucu:

String + 'dan başlayarak 28.01.2013 16:55:40.

Dize + + 28.01.2013 16:55:40 tarihinde tamamlandı.

String + 'dan başlayarak 28.01.2013 16:55:40.

Dize + + 28.01.2013 16:56:02 tarihinde tamamlandı.

Sb'nin başlangıcı 28.01.2013 16:56:02 de sona erdi.

Sb 28.01.2013 16:56:02 tarihinde sona erdi.

0
CathalMF

Genel bir kural olarak, dizenin değerini bir kereden fazla ayarlamak zorunda kalırsam veya dizeye ekler varsa, o zaman dizge oluşturucu olması gerekir. Geçmişte yazmış olduğum uygulamaları gördüm, sadece büyümeye ve büyümeye devam edecek gibi görünen büyük bir bellek ayak izi olan string üreticileri hakkında bilgi aldım. Dizgi oluşturucuyu kullanmak için bu programları değiştirmek, bellek kullanımını önemli ölçüde azaltır. Şimdi string oluşturucu tarafından yemin ederim.

0
user13288

Yaklaşımım her zaman StringBuilder'ı 4 ya da daha fazla dizgiyi birleştirirken kullanmak olmuştur OR Birleşmelerin nasıl olacağını bilemediğimde.

Bu konuda iyi performansla ilgili makale

0
JohnC

StringBuilder muhtemelen tercih edilir. Bunun nedeni, gelecekteki ekler için yer bırakmak için şu anda gerekenden daha fazla alan ayırmasıdır (karakter sayısını belirlersiniz). Ardından, mevcut tampon belleğe uyan gelecekteki ekler, pahalı olabilecek herhangi bir bellek ayırma veya çöp toplama gerektirmez. Genel olarak, StringBuilder'ı karmaşık dize birleştirmesi veya çoklu biçimlendirme için kullanıyorum, ardından veriler tamamlandığında normal bir String'e dönüştürüyorum ve tekrar değişmez bir nesne istiyorum.

0
deemer

Çok fazla dizgi birleştirme yapıyorsanız, bir StringBuilder kullanın. Bir String ile birleştiğinde, daha fazla bellek kullanarak her seferinde yeni bir String yaratırsın.

Alex

0
Alex Fort