Programming

문자열과 StringBuilder

procodes 2020. 5. 5. 20:53
반응형

문자열과 StringBuilder


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

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


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

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

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


다음과 같은 경우 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();

모두 StringBuilder 바람직하다 경우 는 PURE 성능을 위해, 그러나 ... 당신의 코드 패스에 여러 개의 루프, 또는 포크를하고있는 당신이 멀리 얻을 수 있다면, 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를 내부적으로 사용하는 형식 접근 방식 (일반적으로 의심스러운 경우 리플렉터 확인)


이 벤치 마크는 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에게 생성자에 얼마나 큰 버퍼가 있어야하는지 알 수 있습니다.


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가 걸리고 두 번째 반복에는 StringBuilder10ms가 걸렸습니다.

사용 StringBuilder이 더 빠르며 훨씬 빠릅니다.


예, StringBuilder문자열에 대해 반복적 인 작업을 수행하는 동안 성능이 향상됩니다. 모든 인스턴스가 단일 인스턴스로 변경되었으므로와 같은 새 인스턴스를 만드는 대신 많은 시간을 절약 할 수 있습니다 String.

문자열 대 Stringbuilder

  • String

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

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

dotnet mob article : C #의 String Vs StringBuilder를 강력히 추천 합니다.

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


문자열 대 문자열 빌더 :

가장 먼저 알아야 할 것은이 두 계급이 어느 집회에 살고 있습니까?

그래서,

문자열System네임 스페이스에 있습니다.

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

대한 문자열 선언 :

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

대한 의 StringBuilder 선언 :

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

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

stringStringBuilder 의 차이점은 무엇입니까 ?

이 두 가지의 주요 차이점은 다음과 같습니다.

문자열 은 변경할 수 없습니다.

StringBuilder 는 변경 가능합니다.

이제 불변변이 의 차이점을 논의 해 봅시다.

가변 : : 가변을 의미합니다.

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

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

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 번 바꿀 때 일어난 일입니다.

그림을 보자.

여기에 이미지 설명을 입력하십시오

설명 :

이 변수 "name"을 "Rehan"으로 처음 초기화하면,이 변수 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 번 변경했을 때의 일입니다.

그림을 보자. 여기에 이미지 설명을 입력하십시오

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

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

차이점 :

  • String은 System.Text 네임 스페이스에 Stringbuilder로 존재하는 시스템 네임 스페이스에 존재합니다.
  • StringBuilder가 mutabe 인 경우 string은 변경할 수 없습니다.

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

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

출처 : MSDN


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

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

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


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


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


' 마이크로 최적화 극장의 슬픈 비극 '을 고려하십시오 .


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

를 사용하면 StringBuilder수행해야 할 메모리 복사가 훨씬 적습니다. 으로 StringBuilder(int capacity)당신이 마지막이 얼마나 큰 추정 할 수 있다면 당신은 성능을 향상시킬 수 String있을 것입니다. 정확하지 않더라도 StringBuilder성능을 향상시킬 수 있는 용량을 몇 배만 늘리면됩니다.


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

var sb = new StringBuilder(int capacity);

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


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

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


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

예.

StringBuilder sb = 새로운 StringBuilder (50);


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

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


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


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

알렉스


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


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

여기에 좋은 성능 관련 기사


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

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

보시다시피 200,000 회 반복은 22 초가 걸렸지 만 백만 회 반복 StringBuilder은 거의 즉각적이었습니다.

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 추가 완료 28/01/2013 16:56:02.


StringBuilder는 메모리 관점에서 더 나은 성능을 제공합니다. 처리와 관련하여, 실행 시간의 차이는 무시할 수 있습니다.

참고 URL : https://stackoverflow.com/questions/73883/string-vs-stringbuilder

반응형