[C#] 문자열을 연결하는 가장 효율적인 방법은 무엇입니까?

문자열을 연결하는 가장 효율적인 방법은 무엇입니까?



답변

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 가지 유형이 있습니다.

  1. 더하기 ( +) 기호 사용.
  2. 사용 string.Concat().
  3. 사용 string.Join().
  4. 사용 string.Format().
  5. 사용 string.Append().
  6. 사용 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와 함께 사용한다고 신뢰하면 ‘+’로 간단한 문자열 연결이 좋습니다.