문자열을 연결하는 가장 효율적인 방법은 무엇입니까?
답변
이 StringBuilder.Append()
방법은 +
연산자를 사용하는 것보다 훨씬 낫습니다 . 그러나 1000 개 이하의 연결을 실행할 String.Join()
때보 다 훨씬 효율적 이라는 것을 알았 습니다 StringBuilder
.
StringBuilder sb = new StringBuilder();
sb.Append(someString);
유일한 문제 String.Join
는 문자열을 공통 구분 기호로 연결해야한다는 것입니다.
편집 : 로 @ryanversaw는 지적, 당신은 구분 기호를 만들 수 있습니다 string.Empty
.
string key = String.Join("_", new String[]
{ "Customers_Contacts", customerID, database, SessionID });
답변
.NET 성능 전문가 인 Rico Mariani 는이 주제에 대한 기사 를 가지고있었습니다 . 생각하는 것만 큼 간단하지 않습니다. 기본 조언은 다음과 같습니다.
패턴이 다음과 같은 경우 :
x = f1(...) + f2(...) + f3(...) + f4(...)
그것은 하나의 concat이고 zippy입니다 .StringBuilder는 아마 도움이되지 않을 것입니다.
패턴이 다음과 같은 경우 :
if (...) x += f1(...)
if (...) x += f2(...)
if (...) x += f3(...)
if (...) x += f4(...)
그렇다면 아마도 StringBuilder를 원할 것입니다.
이 주장을 뒷받침하는 또 다른 기사 는 Eric Lippert의 한 라인 +
연결에서 수행 된 최적화 에 대해 자세히 설명합니다.
답변
문자열 연결에는 6 가지 유형이 있습니다.
- 더하기 (
+
) 기호 사용. - 사용
string.Concat()
. - 사용
string.Join()
. - 사용
string.Format()
. - 사용
string.Append()
. - 사용
StringBuilder
.
실험 string.Concat()
에서 단어가 1000 (약)보다 적 으면 단어가 1000보다 크면 접근하는 것이 가장 좋은 방법 이라는 것이 입증되었습니다 StringBuilder
.
string.Join () vs. string.Concat ()
여기서 string.Concat 메소드는 빈 구분 기호가있는 string.Join 메소드 호출과 같습니다. 빈 문자열을 추가하는 것은 빠르지 만 그렇게하지 않으면 더 빠르므로 string.Concat 메소드가 더 좋습니다.
답변
에서 Chinh 금지 – StringBuilder에 항상 빠른되지 않습니다 :
엄지 손가락의 규칙
-
합치 할 때 세 미만 동적 문자열 값을하거나, 기존의 문자열 연결을 사용합니다.
-
세 개 이상의 동적 문자열 값을 연결할 때는을 사용하십시오
StringBuilder
. -
여러 문자열 리터럴에서 큰 문자열을 작성할 때는
@
문자열 리터럴 또는 인라인 + 연산자를 사용하십시오.
대부분 의 경우 StringBuilder
가장 좋은 방법이지만, 그 게시물에 표시된 것처럼 적어도 각 상황에 대해 생각해야 할 경우가 있습니다.
답변
루프에서 작업하는 경우 StringBuilder
갈 수있는 방법 일 것입니다. 정기적으로 새 문자열을 작성하는 오버 헤드를 줄입니다. 그러나 한 번만 실행되는 코드에서는 String.Concat
아마 좋습니다.
그러나 Rico Mariani (.NET 최적화 전문가) 는 마지막에 대부분의 경우 추천 하는 퀴즈 를 구성했습니다 String.Format
.
답변
다음은 대규모 NLP 앱에서 10 년 동안 발전한 가장 빠른 방법입니다. IEnumerable<T>
다른 유형 ( Char
, String
)의 구분 기호 가 있거나없는 변형 과 다른 입력 유형이 있지만 배열의 모든 문자열을 구분 기호가없는 단일 문자열로 연결 하는 간단한 경우를 보여줍니다 . 최신 버전은 C # 7 및 .NET 4.7 에서 개발되고 단위 테스트되었습니다 .
성능을 높이려면 두 가지 열쇠가 있습니다. 첫 번째는 필요한 정확한 총 크기를 미리 계산하는 것입니다. 이 단계는 입력이 여기에 표시된 배열 인 경우에는 간단합니다. IEnumerable<T>
대신 처리 하려면 먼저 총계를 계산하기 위해 문자열을 임시 배열로 수집하는 ToString()
것이 좋습니다. 부작용이 발생할 가능성이 있기 때문에 기술적으로 요소 당 두 번 이상 호출하는 것을 피해야 합니다. ‘문자열 조인’작업).
다음으로 최종 문자열의 총 할당 크기를 고려할 때 결과 문자열을 제자리 에 구축하면 성능이 크게 향상됩니다 . 이를 위해서는 String
처음에는 0으로 할당 된 새로운 불변성을 일시적으로 중단시키는 (아마도 논쟁의 여지가있는) 기술이 필요합니다 . 그러나 그러한 논쟁은 제쳐두고 …
… 이것은 생성자에 의한 여분의 할당 및 복사 를 완전히 피하는이 페이지의 유일한 대량 연결 솔루션입니다
String
.
완전한 코드 :
/// <summary>
/// Concatenate the strings in 'rg', none of which may be null, into a single String.
/// </summary>
public static unsafe String StringJoin(this String[] rg)
{
int i;
if (rg == null || (i = rg.Length) == 0)
return String.Empty;
if (i == 1)
return rg[0];
String s, t;
int cch = 0;
do
cch += rg[--i].Length;
while (i > 0);
if (cch == 0)
return String.Empty;
i = rg.Length;
fixed (Char* _p = (s = new String(default(Char), cch)))
{
Char* pDst = _p + cch;
do
if ((t = rg[--i]).Length > 0)
fixed (Char* pSrc = t)
memcpy(pDst -= t.Length, pSrc, (UIntPtr)(t.Length << 1));
while (pDst > _p);
}
return s;
}
[DllImport("MSVCR120_CLR0400", CallingConvention = CallingConvention.Cdecl)]
static extern unsafe void* memcpy(void* dest, void* src, UIntPtr cb);
이 코드는 내가 사용하는 것에서 약간 수정되었다는 것을 언급해야합니다. 원본에서는 실제 복사를 수행하기 위해 C # 에서 cpblk IL 명령어 를 호출합니다 . 여기서 코드의 단순성과 이식성을 위해, 보시 다시피 대신 P / Invoke로 대체했습니다 . x64에서 성능을 높이 려면 ( x86 은 아님) 대신 cpblk 방법 을 사용하는 것이 좋습니다.memcpy
답변
이 MSDN 기사에서 :
시간과 메모리 모두에서 StringBuilder 객체를 만드는 것과 관련된 약간의 오버 헤드가 있습니다. 메모리가 빠른 컴퓨터에서는 약 5 개의 작업을 수행하는 경우 StringBuilder가 유용합니다. 경험상, 10 개 이상의 문자열 연산은 어느 머신에서나 오버 헤드에 대한 오버 헤드에 대한 정당화라고 말합니다.
따라서 10 개 이상의 문자열 작업 / 연결을 수행 해야하는 경우 MSDN을 StringBuilder와 함께 사용한다고 신뢰하면 ‘+’로 간단한 문자열 연결이 좋습니다.