답변:
예, 성능 차이가 중요합니다. 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();
a로컬 변수이고 참조하는 객체가 다른 변수에 할당되지 않은 경우 (다른 스레드에 액세스 가능할 수 있음)이 최적화 시퀀스는이 시퀀스 동안 다른 코드 에서 a액세스 할 수없는 것으로 결정할 수 있습니다. 윤곽; 물질 의 최종 가치 만 . 따라서이 세 줄의 코드를 마치 마치 작성된 것처럼 취급 할 수 있습니다. aa = b + c + d;
모두 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를 내부적으로 사용하는 형식 접근 방식 (일반적으로 의심스러운 경우 리플렉터를 확인하십시오!)
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이 더 빠르며 훨씬 빠릅니다.
이 벤치 마크는 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에게 생성자에 얼마나 큰 버퍼가 있어야하는지 알 수 있습니다.
i.ToString()이다. 따라서 StringBuilder를 사용하면 6 + 1 개의 문자열을 만들어야합니다. 13 개의 문자열 생성을 7 개의 문자열 생성으로 줄였습니다. 그러나 그것은 여전히 그것을 보는 잘못된 방법입니다. 6 개의 숫자 문자열 생성은 관련이 없습니다. 결론 : 단순히 6 개의 문자열을 언급해서는 안됩니다 i.ToString(). 그것들은 효율성 비교의 일부가 아닙니다.
예, StringBuilder문자열에 대해 반복적 인 작업을 수행하는 동안 성능이 향상됩니다. 모든 인스턴스가 단일 인스턴스로 변경되므로 다음과 같은 새 인스턴스를 만드는 대신 많은 시간을 절약 할 수 있습니다.String .
String
System 네임 스페이스StringBuilder (변경 가능한 문자열)
System.Text 네임 스페이스dotnet mob article을 강력히 추천하십시오 : C #의 String Vs StringBuilder 합니다.
관련 스택 오버플로 질문 : C #에서 문자열이 변경되지 않을 때 문자열의 변경 가능성? .
문자열 대 문자열 빌더 :
가장 먼저 알아야 할 것은이 두 계급이 어느 집회에 살고 있습니까?
그래서,
문자열 은System 네임 스페이스에 있습니다.
과
StringBuilder 는System.Text 네임 스페이스에 있습니다.
대한 문자열 선언 :
당신은 포함해야합니다 System네임 스페이스 합니다. 이 같은.
Using System;
과
의 경우 모두 StringBuilder 선언 :
당신은 포함해야합니다 System.text네임 스페이스 합니다. 이 같은.
Using System.text;
이제 실제 질문에 오십시오.
string 과 StringBuilder 의 차이점은 무엇입니까 ?
이 두 가지의 주요 차이점은 다음과 같습니다.
끈 은 변경할 수 없습니다.
과
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 객체가 많이없는 이유는 변경 가능한 이유가 있기 때문입니다. 그것은 시간이 지남에 따라 변한다는 의미입니까?
차이점 :
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가 지적했듯이 루프 내부에서 발생할 가능성이 더 큽니다.
' 마이크로 최적화 극장의 슬픈 비극 '을 고려하십시오 .
문자열 스토리지에 사용하기 전에 EnsureCapacity(int capacity)인스턴스 에서 메소드 호출을 사용하면 성능이 크게 향상되었습니다 StringBuilder. 나는 보통 인스턴스화 후 코드 라인에서 이것을 호출합니다. 다음 StringBuilder과 같이 인스턴스화하는 것과 동일한 효과가 있습니다 .
var sb = new StringBuilder(int capacity);
이 호출은 필요한 메모리를 미리 할당하므로 여러 Append()작업 중에 메모리 할당이 줄어 듭니다 . 필요한 메모리 양을 교육적으로 추측해야하지만 대부분의 응용 프로그램에서는 그렇게 어렵지 않아야합니다. 나는 보통 너무 많은 메모리 (우리는 1k 정도 이야기하고 있습니다)의 측면에서 실수합니다.
EnsureCapacity직후 에 호출 할 필요가 없습니다 StringBuilder. 다음 StringBuilder과 같이 간단히 인스턴스화하십시오 var sb = new StringBuilder(int capacity).
StringBuilder는 실제로 불변이며, StringBuilder에는 버퍼를 내장하여 크기를보다 효율적으로 관리 할 수 있습니다. StringBuilder의 크기를 조정해야 할 때는 힙에서 다시 할당 할 때입니다. 기본적으로 16 자 크기로 생성자에서이를 설정할 수 있습니다.
예.
StringBuilder sb = 새로운 StringBuilder (50);
내 접근 방식은 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.