Rozumiem zalety StringBuilder.
Ale jeśli chcę połączyć 2 ciągi, to zakładam, że lepiej (szybciej) to zrobić bez StringBuildera. Czy to jest poprawne?
W którym momencie (liczba ciągów) lepiej jest używać StringBuilder?
c#
stringbuilder
Shiraz Bhaiji
źródło
źródło
Odpowiedzi:
Gorąco zachęcam do przeczytania Smutnej tragedii teatru mikro-optymalizacji autorstwa Jeffa Atwooda.
Traktuje prostą konkatenację, StringBuilder i inne metody.
Teraz, jeśli chcesz zobaczyć liczby i wykresy, kliknij link;)
źródło
To prawda, możesz znaleźć, dlaczego dokładnie wyjaśniono bardzo dobrze:
http://www.yoda.arachsys.com/csharp/stringbuilder.html
Podsumowując: jeśli możesz połączyć struny za jednym razem, np
var result = a + " " + b + " " + c + ..
lepiej jest bez StringBuilder, ponieważ wykonywana jest tylko kopia (długość otrzymanego ciągu jest obliczana wcześniej);
Dla struktury takiej jak
var result = a; result += " "; result += b; result += " "; result += c; ..
za każdym razem tworzone są nowe obiekty, więc warto rozważyć StringBuilder.
Na koniec artykuł podsumowuje te praktyczne zasady:
źródło
System.String jest niezmiennym obiektem - oznacza to, że za każdym razem, gdy zmodyfikujesz jego zawartość, przydzieli nowy ciąg, a to wymaga czasu (i pamięci?). Używając StringBuilder, modyfikujesz rzeczywistą zawartość obiektu bez przydzielania nowej.
Dlatego używaj StringBuilder, gdy musisz wykonać wiele modyfikacji ciągu.
źródło
Niezupełnie ... powinieneś użyć StringBuilder, jeśli łączysz duże ciągi lub masz wiele konkatenacji, jak w pętli.
źródło
StringBuilder
tylko wtedy, gdy pętla lub konkatenacja stanowi problem ze specyfikacją.string s = "abcd"
, przynajmniej to ostatnia rzecz Słyszałem ... chociaż ze zmiennymi byłby to najprawdopodobniej Concat.a + "hello" + "somethingelse"
i nigdy nie musiałem się tym martwić. Jeśli stanie się to problemem, użyję StringBuilder. Ale przede wszystkim nie martwiłem się tym i spędzałem mniej czasu na pisaniu.Oto prosta aplikacja testowa, aby to udowodnić:
class Program { static void Main(string[] args) { const int testLength = 30000; var StartTime = DateTime.Now; //TEST 1 - String StartTime = DateTime.Now; String tString = "test string"; for (int i = 0; i < testLength; i++) { tString += i.ToString(); } Console.WriteLine((DateTime.Now - StartTime).TotalMilliseconds.ToString()); //result: 2000 ms //TEST 2 - StringBuilder StartTime = DateTime.Now; StringBuilder tSB = new StringBuilder("test string"); for (int i = 0; i < testLength; i++) { tSB.Append(i.ToString()); } Console.WriteLine((DateTime.Now - StartTime).TotalMilliseconds.ToString()); //result: 4 ms Console.ReadLine(); } }
Wyniki:
30 000 iteracji
1000 iteracji
500 iteracji
źródło
Parafrazować
Generalnie używam konstruktora ciągów dla dowolnego bloku kodu, który spowodowałby konkatenację trzech lub więcej ciągów.
źródło
Nie ma ostatecznej odpowiedzi, tylko praktyczne zasady. Moje własne zasady wyglądają mniej więcej tak:
StringBuilder
.StringBuilder
.Jeśli tak nie jest, użyj pliku
StringBuilder
.źródło
Tak. Ale co ważniejsze, użycie wanilii w takich sytuacjach jest znacznie bardziej czytelne
String
. Z drugiej strony używanie go w pętli ma sens i może być tak czytelne, jak konkatenacja.Obchodziłbym się z praktycznymi regułami, które jako próg cytują określoną liczbę konkatenacji. Używanie go w pętlach (i tylko w pętlach) jest prawdopodobnie równie przydatne, łatwiejsze do zapamiętania i ma więcej sensu.
źródło
Ponieważ trudno jest znaleźć wytłumaczenie tego, które nie ma wpływu ani na opinie, ani na walkę o dumę, pomyślałem, że napiszę trochę kodu na LINQpad, aby samemu to przetestować.
Zauważyłem, że używanie łańcuchów o małych rozmiarach zamiast i.ToString () zmienia czasy odpowiedzi (widoczne w małych pętlach).
Test wykorzystuje różne sekwencje iteracji, aby utrzymać pomiary czasu w rozsądnie porównywalnych zakresach.
Skopiuję kod na końcu, abyś mógł spróbować samemu (wyniki.Charts ... Dump () nie będzie działać poza LINQPad).
Dane wyjściowe (oś X: liczba przetestowanych iteracji, oś Y: czas mierzony w taktach):
Sekwencja iteracji: 2, 3, 4, 5, 6, 7, 8, 9, 10
Sekwencja iteracji: 10, 20, 30, 40, 50, 60, 70, 80
Sekwencja iteracji: 100, 200, 300, 400, 500
Kod (napisany przy użyciu LINQPad 5):
void Main() { Test(2, 3, 4, 5, 6, 7, 8, 9, 10); Test(10, 20, 30, 40, 50, 60, 70, 80); Test(100, 200, 300, 400, 500); } void Test(params int[] iterationsCounts) { $"Iterations sequence: {string.Join(", ", iterationsCounts)}".Dump(); int testStringLength = 10; RandomStringGenerator.Setup(testStringLength); var sw = new System.Diagnostics.Stopwatch(); var results = new Dictionary<int, TimeSpan[]>(); // This call before starting to measure time removes initial overhead from first measurement RandomStringGenerator.GetRandomString(); foreach (var iterationsCount in iterationsCounts) { TimeSpan elapsedForString, elapsedForSb; // string sw.Restart(); var str = string.Empty; for (int i = 0; i < iterationsCount; i++) { str += RandomStringGenerator.GetRandomString(); } sw.Stop(); elapsedForString = sw.Elapsed; // string builder sw.Restart(); var sb = new StringBuilder(string.Empty); for (int i = 0; i < iterationsCount; i++) { sb.Append(RandomStringGenerator.GetRandomString()); } sw.Stop(); elapsedForSb = sw.Elapsed; results.Add(iterationsCount, new TimeSpan[] { elapsedForString, elapsedForSb }); } // Results results.Chart(r => r.Key) .AddYSeries(r => r.Value[0].Ticks, LINQPad.Util.SeriesType.Line, "String") .AddYSeries(r => r.Value[1].Ticks, LINQPad.Util.SeriesType.Line, "String Builder") .DumpInline(); } static class RandomStringGenerator { static Random r; static string[] strings; public static void Setup(int testStringLength) { r = new Random(DateTime.Now.Millisecond); strings = new string[10]; for (int i = 0; i < strings.Length; i++) { strings[i] = Guid.NewGuid().ToString().Substring(0, testStringLength); } } public static string GetRandomString() { var indx = r.Next(0, strings.Length); return strings[indx]; } }
źródło
Dopóki możesz fizycznie wpisać liczbę konkatenacji (a + b + c ...), nie powinno to robić dużej różnicy. N do kwadratu (przy N = 10) to 100-krotne spowolnienie, co nie powinno być takie złe.
Duży problem występuje, gdy łączysz setki łańcuchów. Przy N = 100 uzyskujesz 10000-krotne spowolnienie. Co jest dość złe.
źródło
Nie sądzę, aby istniała cienka granica między tym, kiedy używać, a kiedy nie. Chyba że ktoś przeprowadził obszerne testy, aby wyjść ze złotymi warunkami.
Dla mnie nie użyję StringBuilder, jeśli tylko połączę 2 ogromne ciągi. Jeśli istnieje pętla z nieokreśloną liczbą, prawdopodobnie tak będzie, nawet jeśli pętla może być niewielka.
źródło
Pojedyncza konkatenacja nie jest warta używania StringBuilder. Zwykle stosuję 5 konkatenacji jako praktyczną zasadę.
źródło