문제

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

도움이 되었습니까?

해결책

그만큼 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 성능 전문가인 는 기사 바로 이 주제에 대해.의심하는 것만큼 간단하지 않습니다.기본적인 조언은 이렇습니다.

패턴이 다음과 같은 경우:

x = f1(...) + f2(...) + f3(...) + f4(...)

그것은 하나의 연결이고 활기차기 때문에 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 사용되어야한다.

자세한 내용은 여기를 확인하세요. 대지.

문자열.Join() 대 문자열.Concat()

여기서 string.Concat 메서드는 빈 구분 기호를 사용한 string.Join 메서드 호출과 동일합니다.빈 문자열을 추가하는 것은 빠르지만 추가하지 않는 것이 훨씬 더 빠릅니다. 문자열.연결 여기서는 방법이 더 나을 것입니다.

에서 Chinh Do - StringBuilder가 항상 빠른 것은 아닙니다.:

경험 법칙

  • 3개 이하의 동적 문자열 값을 연결하는 경우 기존 문자열 연결을 사용합니다.

  • 3개 이상의 동적 문자열 값을 연결할 때는 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);

이 코드에는 내가 사용하는 코드가 약간 수정되었다는 점을 언급하고 싶습니다.원작에서는 내가 ~을 부르다 cpblk IL 지시 ~에서 씨# 실제 복사를 하려고 합니다.여기 코드의 단순성과 이식성을 위해 이를 P/Invoke로 대체했습니다. memcpy 대신, 보시다시피.x64에서 최고의 성능을 얻으려면(하지만 x86은 아닐 수도 있어요) 당신은 cpblk 대신 방법.

이것으로부터 MSDN 기사:

시간과 메모리 모두에서 StringBuilder 객체를 만드는 것과 관련된 오버 헤드가 있습니다.빠른 메모리가있는 기계에서는 약 5 개의 작업을 수행하는 경우 StringBuilder가 가치가 있습니다.경험상, 나는 10 개 이상의 문자열 작업이 모든 기계의 오버 헤드, 심지어 느린 기계의 오버 헤드에 대한 정당성이라고 말합니다.

따라서 MSDN을 신뢰한다면 10개 이상의 문자열 작업/연결을 수행해야 하는 경우 StringBuilder를 사용하십시오. 그렇지 않으면 '+'를 사용한 간단한 문자열 연결이 좋습니다.

다른 답변에 추가하여 다음 사항을 명심하십시오. StringBuilder는 할당할 초기 메모리 양을 알 수 있습니다..

그만큼 용량 매개변수는 현재 인스턴스에서 할당한 메모리에 저장할 수 있는 최대 문자 수를 정의합니다.그 값은 다음에 할당됩니다. 용량 재산.현재 인스턴스에 저장할 문자 수가 이 값을 초과하는 경우 용량 값이 있으면 StringBuilder 개체는 이를 저장하기 위해 추가 메모리를 할당합니다.

만약에 용량 0이면 구현별 기본 용량이 사용됩니다.

사전 할당되지 않은 StringBuilder에 반복적으로 추가하면 일반 문자열을 반복적으로 연결하는 것처럼 불필요한 할당이 많이 발생할 수 있습니다.

최종 문자열의 길이를 알고 있고 간단하게 계산할 수 있거나 일반적인 경우에 대해 교육적인 추측을 할 수 있는 경우(너무 많이 할당하는 것이 반드시 나쁜 것은 아닙니다) 이 정보를 생성자 또는 생성자에게 제공해야 합니다. 용량 재산. 특히 StringBuilder를 내부적으로 동일한 작업을 수행하는 String.Concat과 같은 다른 메서드와 비교하기 위해 성능 테스트를 실행할 때.비교에 StringBuilder 사전 할당이 포함되지 않은 온라인 테스트는 모두 잘못된 것입니다.

크기에 대해 어떤 종류의 추측도 할 수 없다면 아마도 사전 할당을 제어하기 위한 자체 선택적 인수가 있어야 하는 유틸리티 함수를 작성하고 있을 것입니다.

또한 + 연결하는 경우 연산자 문자열 리터럴.

+ 연산자를 사용하여 문자열 리터럴이나 문자열 상수를 연결하면 컴파일러는 단일 문자열을 만듭니다.런타임 연결이 발생하지 않습니다.

어떻게:여러 문자열 연결(C# 프로그래밍 가이드)

다음은 여러 문자열을 연결하는 또 하나의 대체 솔루션일 수 있습니다.

String str1 = "sometext";
string str2 = "some other text";

string afterConcate = $"{str1}{str2}";

문자열 보간

가장 효율적인 방법은 다음과 같이 StringBuilder를 사용하는 것입니다.

StringBuilder sb = new StringBuilder();
sb.Append("string1");
sb.Append("string2");
...etc...
String strResult = sb.ToString();

@존지:String.Concat은 몇 가지 작은 것들이 있으면 괜찮습니다.그러나 메가바이트의 데이터를 연결하는 경우 프로그램이 중단될 가능성이 높습니다.

이 두 가지 코드를 시도하면 해결책을 찾을 수 있습니다.

 static void Main(string[] args)
    {
        StringBuilder s = new StringBuilder();
        for (int i = 0; i < 10000000; i++)
        {
            s.Append( i.ToString());
        }
        Console.Write("End");
        Console.Read();
    }

static void Main(string[] args)
    {
        string s = "";
        for (int i = 0; i < 10000000; i++)
        {
            s += i.ToString();
        }
        Console.Write("End");
        Console.Read();
    }

첫 번째 코드는 매우 빠르게 종료되고 메모리 양이 넉넉하다는 것을 알게 될 것입니다.

두 번째 코드는 아마도 메모리는 괜찮겠지만 시간이 더 오래 걸릴 것입니다...더 길게.따라서 많은 사용자를 위한 애플리케이션이 있고 속도가 필요한 경우 1st를 사용하십시오.단기 단일 사용자용 앱이 있는 경우 둘 다 사용할 수 있거나 두 번째가 개발자에게 더 "자연스럽"을 것입니다.

건배.

System.String은 변경할 수 없습니다.문자열 변수의 값을 수정하면 새 메모리가 새 값에 할당되고 이전 메모리 할당이 해제됩니다.System.StringBuilder는 수정된 문자열에 대해 별도의 메모리 위치를 할당하지 않고 다양한 작업을 수행할 수 있는 가변 문자열 개념을 갖도록 설계되었습니다.

또 다른 해결책:

루프 내에서 문자열 대신 List를 사용하십시오.

List<string> lst= new List<string>();

for(int i=0; i<100000; i++){
    ...........
    lst.Add(...);
}
return String.Join("", lst.ToArray());;

그것은 매우 매우 빠릅니다.

실제로는 사용 패턴에 따라 다릅니다.string.Join, string,Concat 및 string.Format 간의 자세한 벤치마크는 여기에서 찾을 수 있습니다. String.Format은 집중적 로깅에 적합하지 않습니다.

(실제로 제가 드린 답변과 동일합니다. 이것 질문)

문자열이 두 개인 경우 StringBuilder를 사용하고 싶지 않을 것입니다.StringBuilder 오버헤드가 여러 문자열을 할당하는 오버헤드보다 작은 임계값이 있습니다.

따라서 2-3개 이상의 문자열에 대해서는 다음을 사용하십시오. DannySmurf의 코드.그렇지 않으면 + 연산자를 사용하세요.

코드에 따라 다릅니다.일반적으로 StringBuilder가 더 효율적이지만 몇 개의 문자열만 연결하여 한 줄에 모두 수행하는 경우 코드 최적화를 통해 이를 처리할 수 있습니다.코드가 어떻게 보이는지 생각하는 것도 중요합니다.더 큰 세트의 경우 StringBuilder를 사용하면 읽기가 더 쉬워지고, 작은 세트의 경우 StringBuilder는 불필요한 혼란만 추가합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top