it-swarm-ko.tech

문자열과 StringBuilder

StringStringBuilder (StringBuilder 변경 가능)의 차이점을 이해하지만 둘 사이에 큰 성능 차이가 있습니까?

내가하고있는 프로그램에는 대소 문자 중심 문자열 추가 (500+)가 많이 있습니다. StringBuilder을 사용하는 것이 더 나은 선택입니까?

204
Kuvo

예, 성능 차이가 중요합니다. KB 문서 " Visual C #에서 문자열 연결 성능을 향상시키는 방법 "을 참조하십시오.

나는 항상 명확성을 위해 먼저 코딩을 시도한 다음 나중에 성능을 최적화합니다. 다른 방법으로하는 것보다 훨씬 쉽습니다! 그러나 두 응용 프로그램 간의 응용 프로그램에서 엄청난 성능 차이를 보았으므로 이제 조금 더 신중하게 생각합니다.

운 좋게도 코드에서 성능 분석을 실행하여 시간을 소비하는 위치를 확인한 다음 필요한 경우 StringBuilder을 사용하도록 수정하는 것이 비교적 간단합니다.

225
Jay Bazuzi

다음과 같은 경우 Gillian이 4 문자열에 대해 말한 내용을 분명히하십시오.

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

문자열과 더하기 연산자를 사용하면 더 빠릅니다. 왜냐하면 Eric이 지적한 것처럼 Java와 같이 내부적으로 StringBuilder를 자동으로 사용하기 때문입니다 (실제로 StringBuilder도 사용하는 기본 요소를 사용함)

그러나 당신이하고있는 일이 더 가까이 있다면 :

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

그런 다음 StringBuilder를 명시 적으로 사용해야합니다. .Net은 StringBuilder를 자동으로 생성하지 않습니다. 무의미하기 때문입니다. 각 줄의 끝에서 "a"는 (불변) 문자열이어야하므로 각 줄에 StringBuilder를 생성하고 배치해야합니다. 속도를 높이려면 빌드가 완료 될 때까지 동일한 StringBuilder를 사용해야합니다.

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를 사용하는 것이 좋습니다 IF 코드 루프에서 여러 루프 또는 포크를 수행하고 있습니다. 그러나 SINGLE = 문자열 선언, 그것은 훨씬 더 성능이 좋습니다.

예를 들면 다음과 같습니다.

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

보다 성능이 좋다

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..

이 경우 StringBuild를 유지 관리하기 쉬운 것으로 간주 할 수 있지만 단일 문자열 선언보다 성능이 우수하지는 않습니다.

그래도 10에서 9 번 ... 문자열 빌더를 사용하십시오.

참고 사항 : string + var는 string보다 성능이 뛰어납니다. (일반적으로) StringBuilder를 내부적으로 사용하는 형식 접근 방식 (일반적으로 의심스러운 경우 리플렉터를 확인하십시오!)

28
calebjenkins

이 벤치 마크는 3 개 이하의 문자열을 결합 할 때 규칙적인 연결이 더 빠름을 보여줍니다.

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

StringBuilder는 특히 500 개의 문자열을 함께 추가하는 경우 메모리 사용량을 크게 개선 할 수 있습니다.

다음 예제를 고려하십시오.

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

메모리는 어떻게 되나요? 다음과 같은 문자열이 생성됩니다.

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"

문자열 끝에 5 개의 숫자를 추가하여 13 개의 문자열 개체를 만들었습니다! 그리고 그들 중 12 명은 쓸모가 없었습니다! 와!

StringBuilder가이 문제를 해결합니다. 우리가 자주 듣는 것처럼 "변경 가능한 문자열"이 아닙니다 (. NET의 모든 문자열은 변경할 수 없습니다). 내부 버퍼, char 배열을 유지하여 작동합니다. Append () 또는 AppendLine ()을 호출하면 char 배열 끝의 빈 공간에 문자열이 추가됩니다. 배열이 너무 작 으면 더 큰 새 배열을 작성하고 거기에 버퍼를 복사합니다. 따라서 위의 예에서 StringBuilder는 버퍼 크기에 따라 문자열에 5 개의 추가 항목을 모두 포함하는 단일 배열 만 필요할 수 있습니다. StringBuilder에게 생성자에 얼마나 큰 버퍼가 있어야하는지 알 수 있습니다.

23
Matt Trunnell

String 연결 대 StringBuilder을 사용할 때 속도의 차이를 보여주는 간단한 예 :

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");

결과:

문자열 연결 사용 : 15423 밀리 초

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");

결과:

StringBuilder 사용 : 10 밀리 초

결과적으로 첫 번째 반복에는 15423ms가 걸리고 StringBuilder을 사용한 두 번째 반복에는 10ms가 걸렸습니다.

StringBuilder을 사용하는 것이 더 빠르며 훨씬 빠릅니다.

21
Diizzy

예, StringBuilder은 문자열에 대해 반복 된 작업을 수행하는 동안 더 나은 성능을 제공합니다. String과 같은 새 인스턴스를 만드는 대신 많은 시간을 절약 할 수 있으므로 단일 인스턴스에 대한 모든 변경 사항이 적용되기 때문입니다.

문자열 대 Stringbuilder

  • String

    1. System 네임 스페이스에서
    2. 불변 (읽기 전용) 인스턴스
    3. 지속적인 가치 변화가 발생하면 성능이 저하됩니다
    4. 스레드 안전
  • StringBuilder (변경 가능한 문자열)

    1. System.Text 네임 스페이스 아래
    2. 가변 인스턴스
    3. 기존 인스턴스가 새로 변경되었으므로 더 나은 성능을 보여줍니다

Dotnet mob article : C #의 String Vs StringBuilder 를 강력히 권장합니다.

관련 스택 오버플로 질문 : C #에서 문자열이 변경되지 않을 때 문자열의 변경 가능성? .

12
Shamseer K

StringBuilder는 사용되는 추가 메모리 비용으로 할당 및 할당 수를 줄입니다. 올바르게 사용하면 결과를 찾을 때까지 컴파일러가 더 크고 더 큰 문자열을 반복해서 할당 할 필요가 없습니다.

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 System 네임 스페이스에 있습니다.

StringBuilder System.Text 네임 스페이스에 있습니다.

string 선언의 경우 :

System 네임 스페이스를 포함해야합니다. 이 같은. Using System;

StringBuilder 선언의 경우 :

System.text 네임 스페이스를 포함해야합니다. 이 같은. Using System.text;

이제 실제 질문에 오십시오.

string StringBuilder 의 차이점은 무엇입니까?

이 둘의 주요 차이점은 다음과 같습니다.

string 은 변경할 수 없습니다.

StringBuilder 는 변경 가능합니다.

이제 불변 불변 의 차이점에 대해 설명하겠습니다.

Mutable : : 변경 가능을 의미합니다.

Immutable : : 변경할 수 없음을 의미합니다.

예 :

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."
        }
    }
}

이 경우 동일한 객체를 5 번 변경하겠습니다.

명백한 질문은 바로 이것입니다! 동일한 문자열을 5 번 변경하면 실제로 발생합니다.

이것은 같은 문자열을 5 번 바꿀 때 일어난 일입니다.

그림을 보자.

enter image description here

설명 :

이 변수 "name"을 "Rehan"i-e string name = "Rehan"로 처음 초기화하면이 변수는 스택 "name"에서 생성되고 해당 "Rehan"값을 가리 킵니다. 이 줄이 실행 된 후 : "name = name +"Shah "참조 변수는 더 이상 해당 개체"Rehan "을 가리 키지 않으며 이제"Shah "를 가리 킵니다.

따라서 string은 변경할 수 없으므로 메모리에 객체를 만든 후에는 변경할 수 없습니다.

따라서 name 변수를 연결하면 이전 객체가 메모리에 남아 있고 다른 새 문자열 객체가 생성됩니다.

위 그림에서 우리는 5 개의 물체를 가지고 있습니다. 4 개의 물체는 버려져 전혀 사용되지 않습니다. 그들은 여전히 ​​메모리에 남아 있으며 메모리 양을 차지합니다. "가비지 콜렉터"는 메모리에서 해당 자원을 정리합니다.

따라서 문자열을 반복해서 조작 할 때마다 문자열의 경우 생성 된 많은 객체가 메모리에 남아 있습니다.

이것이 변수 Variable의 이야기입니다.

이제 StringBuilder Object를 살펴 보겠습니다. 예 :

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."
        }
    }
}

이 경우 동일한 객체를 5 번 변경하겠습니다.

명백한 질문은 바로 이것입니다! 동일한 StringBuilder를 5 번 변경하면 실제로 발생하는 상황입니다.

이것은 동일한 StringBuilder를 5 번 변경했을 때의 일입니다.

그림을 보자. enter image description here

설명 : StringBuilder 객체의 경우. 새 객체를 얻지 못할 것입니다. 동일한 객체가 메모리에서 변경되므로 객체를 변경하고 10,000 번이라고해도 여전히 하나의 stringBuilder 객체가 있습니다.

가비지 객체 또는 비 참조 stringBuilder 객체가 많이없는 이유는 변경 가능한 이유가 있기 때문입니다. 그것은 시간이 지남에 따라 변한다는 의미입니까?

차이 :

  • String은 System.Text 네임 스페이스에 Stringbuilder가있는 시스템 네임 스페이스에 있습니다.
  • stringBuilder가 mutabe 인 경우 string은 변경할 수 없습니다.
7
Rehan Shah

String 또는 StringBuilder 객체에 대한 연결 작업의 성능은 메모리 할당 빈도에 따라 다릅니다. 문자열 연결 작업은 항상 메모리를 할당하는 반면 StringBuilder 연결 작업은 StringBuilder 객체 버퍼가 너무 작아서 새 데이터를 수용 할 수없는 경우에만 메모리를 할당합니다. 따라서 고정 된 수의 String 객체가 연결된 경우 연결 작업에 String 클래스가 선호됩니다. 이 경우 컴파일러에서 개별 연결 작업을 단일 작업으로 결합 할 수도 있습니다. 임의의 수의 문자열이 연결된 경우 연결 작업에 StringBuilder 객체가 선호됩니다. 예를 들어, 루프가 임의의 수의 사용자 입력 문자열을 연결하는 경우.

출처 : MSDN

4
user487069

StringBuilder은 상수가 아닌 많은 값에서 문자열을 작성하는 것이 좋습니다.

HTML 또는 XML 문서 또는 다른 텍스트 덩어리에 여러 줄의 값과 같은 많은 상수 값으로 문자열을 작성하는 경우 거의 모든 컴파일러가 수행하기 때문에 동일한 문자열에 추가하는 것만으로도 벗어날 수 있습니다 "constantfolding"은 상수 조작이 많을 때 구문 분석 트리를 줄이는 프로세스입니다 (int minutesPerYear = 24 * 365 * 60와 같은 것을 쓸 때도 사용됩니다). 상수가 아닌 값이 서로 추가 된 간단한 경우 .NET 컴파일러는 코드를 StringBuilder와 비슷한 것으로 줄입니다.

그러나 컴파일러가 추가를 더 간단한 것으로 줄일 수없는 경우 StringBuilder을 원할 것입니다. fizch가 지적했듯이 루프 내부에서 발생할 가능성이 더 큽니다.

3
JasonTrue
2
Jim G.

연결에 문자열을 사용하면 O(n^2) 정도의 런타임 복잡성이 발생할 수 있습니다.

StringBuilder을 사용하면 수행해야 할 메모리 복사가 훨씬 줄어 듭니다. StringBuilder(int capacity)을 사용하면 최종 String의 크기를 추정 할 수 있으면 성능을 향상시킬 수 있습니다. 정확하지 않더라도 성능에 도움이 될 수있는 StringBuilder 용량을 몇 번만 늘리면됩니다.

2
Steve g

문자열 저장에 사용하기 전에 StringBuilder 인스턴스에서 EnsureCapacity(int capacity) 메서드 호출을 사용하면 성능이 크게 향상되었습니다. 나는 보통 인스턴스화 후 코드 라인에서 이것을 호출합니다. StringBuilder을 다음과 같이 인스턴스화하는 것과 같은 효과가 있습니다.

var sb = new StringBuilder(int capacity);

이 호출은 필요한 메모리를 미리 할당하므로 여러 Append() 작업 중에 적은 메모리 할당이 발생합니다. 필요한 메모리 양을 교육적으로 추측해야하지만 대부분의 응용 프로그램에서는 그렇게 어렵지 않아야합니다. 나는 보통 너무 많은 메모리 (우리는 1k 정도 이야기하고 있습니다)의 측면에서 실수합니다.

2
Jason Jackson

함께 추가 해야하는 4 개 이상의 문자열이 있으면 StringBuilder가 더 빠릅니다. 또한 AppendLine과 같은 멋진 작업을 수행 할 수 있습니다.

2
Gilligan

.NET에서 StringBuilder는 여전히 문자열을 추가하는 것보다 빠릅니다. Java에서는 문자열을 추가 할 때 후드 아래에 StringBuffer 만 생성하므로 실제로 차이는 없습니다. 왜 그들이 .NET에서 아직 이것을하지 않았는지 잘 모르겠습니다.

2
Eric Z Beard

StringBuilder는 실제로 불변이며, StringBuilder에는 버퍼를 내장하여 크기를보다 효율적으로 관리 할 수 ​​있습니다. StringBuilder의 크기를 조정해야 할 때는 힙에서 다시 할당 될 때입니다. 기본적으로 16 자 크기로 생성자에서이를 설정할 수 있습니다.

예.

StringBuilder sb = 새로운 StringBuilder (50);

1
capgpilk

이전 답변 외에도 이와 같은 문제를 생각할 때 항상 가장 먼저하는 일은 작은 테스트 응용 프로그램을 만드는 것입니다. 이 앱 내에서 두 시나리오 모두에 대해 타이밍 테스트를 수행하고 어느 것이 더 빠른지 직접 확인하십시오.

IMHO, 500 개 이상의 문자열 항목을 추가하면 반드시 StringBuilder를 사용해야합니다.

1
RichS

문자열 연결은 더 많은 비용이 듭니다. Java에서는 필요에 따라 StringBuffer 또는 StringBuilder를 사용할 수 있습니다. 동기화되고 스레드 안전 구현을 원하면 StringBuffer로 이동하십시오. 이것은 문자열 연결보다 빠릅니다.

동기화 또는 스레드 안전 구현이 필요하지 않은 경우 StringBuilder로 이동하십시오. 이것은 동기화 연결 오버 헤드가 없으므로 문자열 연결보다 빠르며 StringBuffer보다 빠릅니다.

1
raffimd

StringBuilder이 훨씬 더 효율적이지만 많은 양의 문자열 수정을 수행하지 않으면 성능이 저하되지 않습니다.

아래는 성능 예제를 제공하는 간단한 코드입니다. 보시다시피 큰 반복에 들어갈 때 실제로 성능이 크게 향상되기 시작합니다.

보시다시피 StringBuilder을 사용한 백만 회 반복은 거의 즉각적인 반면 200,000 회 반복은 22 초가 걸렸습니다.

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();

위 코드의 결과 :

문자열 시작 + 28/01/2013 16:55:40.

완성 된 문자열 + 28/01/2013 16:55:40.

문자열 시작 + 28/01/2013 16:55:40.

완성 된 문자열 + 28/01/2013 16:56:02.

Sb의 시작 부분은 28/01/2013 16:56:02에 추가됩니다.

완성 된 Sb 추가 (2013 년 1 월 28 일 16:56:02).

0
CathalMF

일반적으로 문자열 값을 두 번 이상 설정해야하거나 문자열에 추가 된 항목이 있으면 문자열 빌더 여야합니다. 나는 계속해서 성장하고 성장하는 것처럼 보이는 거대한 메모리 공간을 가진 문자열 빌더에 대해 배우기 전에 과거에 작성한 응용 프로그램을 보았습니다. 문자열 작성기를 사용하도록 이러한 프로그램을 변경하면 메모리 사용량이 크게 줄어 듭니다. 이제는 문자열 빌더로 맹세합니다.

0
user13288

내 접근 방식은 4 개 이상의 문자열을 연결할 때 항상 StringBuilder를 사용하는 것입니다. OR 연결이 어떻게 수행되는지 모를 때.

여기에 좋은 성능 관련 기사

0
JohnC

StringBuilder가 바람직 할 것입니다. 그 이유는 향후 추가를위한 공간을 확보하기 위해 현재 필요한 것보다 많은 공간을 할당하기 때문입니다 (문자 수 설정). 그런 다음 현재 버퍼에 맞는 향후 추가에는 메모리 할당이나 가비지 수집이 필요하지 않으므로 비용이 많이들 수 있습니다. 일반적으로 복잡한 문자열 연결 또는 여러 형식에 StringBuilder를 사용하고 데이터가 완료되면 일반 문자열로 변환하고 불변의 객체를 다시 원합니다.

0
deemer

많은 문자열 연결을 수행하는 경우 StringBuilder를 사용하십시오. 문자열과 연결하면 더 많은 메모리를 사용하여 매번 새 문자열을 만듭니다.

알렉스

0
Alex Fort