programing

문자열을 연결하는 가장 효율적인 방법?

newnotes 2023. 4. 10. 22:11
반응형

문자열을 연결하는 가장 효율적인 방법?

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

Rico Mariani, 그.NET Performance 전문가가 바로 이 주제에 대한 기사를 실었습니다.그것은 생각만큼 간단하지 않다.기본적인 조언은 다음과 같습니다.

패턴이 다음과 같은 경우:

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

그것은 하나의 콘센트이고, 그것은 zippy입니다.String Builder는 아마 도움이 되지 않을 것입니다.

패턴이 다음과 같은 경우:

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

String Builder가 필요할 수도 있습니다.

그러나주장을 뒷받침하는 또 다른 기사는 Eric Lippert가 한 줄에서 수행한 최적화에 대해 설명한 것입니다.+상세하게 접속합니다.

StringBuilder.Append().+이하의 을 실행할 때 1000개 이하의 연결을 실행할 때 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 });

문자열 연결에는 6가지 유형이 있습니다.

  1. 사용( 「 )+ ★★★★★★ 。
  2. 「」를 사용합니다.string.Concat().
  3. 「」를 사용합니다.string.Join().
  4. 「」를 사용합니다.string.Format().
  5. 「」를 사용합니다.string.Append().
  6. 「」를 사용합니다.StringBuilder.

string.Concat()일 경우, (약) 일 경우 (약) 이상일 경우 1000(약) 이상일 경우 (약)으로 접근하는 것이 가장 좋습니다.StringBuilder사용해야 합니다.

자세한 것은, 이 사이트를 참조해 주세요.

string.Join() vs string.Concat()

스트링.여기서 Concat 메서드는 문자열과 동일합니다.빈 구분 기호를 사용하여 메서드를 호출합니다.빈 문자열을 추가하는 것은 빠르지만 추가하지 않는 것이 더 빠르기 때문에 문자열은 더 빠릅니다.여기서는 콘캣 방식이 더 나을 것 같아요.

Chinh Do - String Builder가 항상 빠른 것은 아닙니다.

경험칙

  • 3개 이하의 동적 문자열 값을 연결할 때는 기존 문자열 연결을 사용하십시오.

  • 3개 이상의 동적 문자열 값을 연결할 경우StringBuilder.

  • 리터럴로 큰는 이 중 합니다.@인라인+인라인+인텔+인텔+인텔+인텔+인쇄.

대부분의 경우StringBuilder최선의 선택입니다만, 그 투고에 나타나 있듯이, 적어도 각각의 상황을 생각해야 할 경우가 있습니다.

을 하고 있는 「루프 조작」을 실시합니다.StringBuilder새로운 스트링을 정기적으로 작성하는 데 드는 오버헤드를 줄일 수고를 덜 수고를 덜 수 있습니다.,되지 않는 String.Concat아마 괜찮을 거예요.

단, Rico Mariani(.NET 최적화 전문가)는 마지막에 대부분의 경우 추천하는 퀴즈를 만들었습니다.String.Format.

이것은 제가 10년 동안 개발한 대규모 NLP 앱 중 가장 빠른 방법입니다.은 있어요.IEnumerable<T>하거나 포함하지 않음)Char,String)는 배열 모든 문자열을 구분 없이1개의 문자열로 연결하는 간단한 예를 나타냅니다.최신 버전은 C#7 C#7에서 개발 및 유닛테스트되고 있습니다.NET 4.7

퍼포먼스 향상에는 두 가지 키가 있습니다.첫 번째는 필요한 총 사이즈를 사전에 계산하는 것입니다.이 순서는 입력이 다음과 같이 배열일 경우 간단합니다.<고객명>님의 IEnumerable<T>그, 우선 것이 이은, 「」, 「」, 「」, 「」, 「」, 「」, 「」의 호출을 필요합니다).ToString()기술적으로, 부작용의 가능성을 고려할 때, 그렇게 하면 '문자열 결합' 연산의 예상 의미를 변경할 수 있기 때문에 요소당 두 번 이상이다.

다음으로, 최종 문자열의 총 할당 크기를 고려할 때 결과 문자열을 내부구축함으로써 성능이 가장 크게 향상됩니다.이를 위해서는 (아마도 논란이 있을 수 있는) 새로운 제품의 불변성을 일시적으로 중단하는 기술이 필요합니다.String0으로 하다

...이 페이지에서는, 이 솔루션만이, 추가의 할당과 복사를 완전하게 회피할 수 있는 유일한 벌크 접속 솔루션인 것에 주의해 주세요.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로 대체했습니다.memcpy보다시피요.x64(x86은 아닐 수도 있음)에서 최고의 성능을 얻으려면 대신 cpblk 방법을 사용할 수 있습니다.

MSDN 기사:

StringBuilder 오브젝트 작성과 관련된 오버헤드가 시간과 메모리 모두에서 발생합니다.고속 메모리를 탑재한 머신에서는 String Builder를 5회 정도 조작하면 도움이 됩니다.경험에 비추어 볼 때 10개 이상의 문자열 연산은 느린 기계라도 모든 기계에서 오버헤드를 정당화할 수 있습니다.

따라서 MSDN을 신뢰하는 경우 String Builder를 사용하여 10개 이상의 문자열 조작/연결을 수행해야 하는 경우 String Builder를 사용합니다.그렇지 않은 경우 '+'로 구성된 단순한 문자열로 충분합니다.

이 2개의 코드를 시험해 보면 해결책을 찾을 수 있습니다.

 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();
    }

첫 번째 코드가 매우 빨리 종료되고 메모리가 대량으로 저장된다는 것을 알게 될 것입니다.

두 번째 코드는 기억은 괜찮겠지만 시간이 더 걸릴 거야훨씬 더 오래요따라서 많은 사용자를 위한 애플리케이션을 가지고 있고 속도가 필요한 경우 첫 번째 애플리케이션을 사용하십시오.단기간 1사용자용 앱이 있다면 둘 다 사용할 수 있거나 개발자에게는 2번째 앱이 더 '자연스러운' 앱이 될 수 있습니다.

건배.

때 꼭 짚고 넘어가야 합니다.+연산자(문자열 리터럴을 연결하는 경우)를 지정합니다.

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

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

다른 답변에 덧붙여 String Builder에 할당하는 메모리의 초기 용량을 통지할 수 있다는 점에 유의하십시오.

capacity 파라미터는 현재 인스턴스에 의해 할당된 메모리에 저장할 수 있는 최대 문자 수를 정의합니다. 값은 Capacity 속성에 할당됩니다.현재 인스턴스에 저장할 문자 수가 이 용량 값을 초과하면 StringBuilder 개체는 추가 메모리를 할당하여 저장합니다.

용량이 0인 경우 구현 고유의 기본 용량이 사용됩니다.

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

최종 문자열의 길이를 알고 있거나, 그것을 3차적으로 계산할 수 있거나, 일반적인 케이스에 대해 지식 있는 추측을 할 수 있는 경우(너무 많은 할당이 반드시 나쁜 것은 아님)에는 이 정보를 컨스트럭터 또는 Capacity 속성에 제공해야 합니다.특히 String Builder를 String 등의 다른 메서드와 비교하기 위한 성능 테스트를 실행하는 경우.Concat, 내부적으로 동일한 작업을 수행합니다.비교에 String Builder 사전 할당이 포함되지 않은 온라인 테스트는 잘못된 것입니다.

크기를 추측할 수 없는 경우 사전 할당을 제어하는 자체 선택적 인수를 가진 유틸리티 함수를 작성해야 합니다.

다음에, 복수의 문자열을 접속하기 위한 대체 솔루션을 1개 더 나타냅니다.

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

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

문자열 보간

또 다른 솔루션:

루프 내에서는 문자열 대신 List를 사용합니다.

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

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

그것은 매우 빠르다.

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

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

@jonzy:스트링콩카트는 몇 가지 작은 것이 있으면 괜찮습니다.그러나 메가바이트의 데이터를 연결할 경우 프로그램이 엉망이 될 수 있습니다.

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

이 페이지의 모든 방법을 테스트하고 최종적으로 가장 빠르고 메모리 비용도 적게 드는 솔루션을 개발했습니다.

주의: Framework 4.8에서 테스트 완료

여기에 이미지 설명 입력

 [MemoryDiagnoser]
public class StringConcatSimple
{
    private string
        title = "Mr.", firstName = "David", middleName = "Patrick", lastName = "Callan";

    [Benchmark]
    public string FastConcat()
    {
        return FastConcat(
            title, " ", 
            firstName, " ",
            middleName, " ", 
            lastName);
    }

    [Benchmark]
    public string StringBuilder()
    {
        var stringBuilder =
            new StringBuilder();

        return stringBuilder
            .Append(title).Append(' ')
            .Append(firstName).Append(' ')
            .Append(middleName).Append(' ')
            .Append(lastName).ToString();
    }

    [Benchmark]
    public string StringBuilderExact24()
    {
        var stringBuilder =
            new StringBuilder(24);

        return stringBuilder
            .Append(title).Append(' ')
            .Append(firstName).Append(' ')
            .Append(middleName).Append(' ')
            .Append(lastName).ToString();
    }

    [Benchmark]
    public string StringBuilderEstimate100()
    {
        var stringBuilder =
            new StringBuilder(100);

        return stringBuilder
            .Append(title).Append(' ')
            .Append(firstName).Append(' ')
            .Append(middleName).Append(' ')
            .Append(lastName).ToString();
    }

    [Benchmark]
    public string StringPlus()
    {
        return title + ' ' + firstName + ' ' +
            middleName + ' ' + lastName;
    }

    [Benchmark]
    public string StringFormat()
    {
        return string.Format("{0} {1} {2} {3}",
            title, firstName, middleName, lastName);
    }

    [Benchmark]
    public string StringInterpolation()
    {
        return
        $"{title} {firstName} {middleName} {lastName}";
    }

    [Benchmark]
    public string StringJoin()
    {
        return string.Join(" ", title, firstName,
            middleName, lastName);
    }

    [Benchmark]
    public string StringConcat()
    {
        return string.
            Concat(new String[]
            { title, " ", firstName, " ",
                middleName, " ", lastName });
    }
}

네, 안전하지 않습니다.

public static unsafe string FastConcat(string str1, string str2, string str3, string str4, string str5, string str6, string str7)
    {
        var capacity = 0;

        var str1Length = 0;
        var str2Length = 0;
        var str3Length = 0;
        var str4Length = 0;
        var str5Length = 0;
        var str6Length = 0;
        var str7Length = 0;

        if (str1 != null)
        {
            str1Length = str1.Length;
            capacity = str1Length;
        }

        if (str2 != null)
        {
            str2Length = str2.Length;
            capacity += str2Length;
        }

        if (str3 != null)
        {
            str3Length = str3.Length;
            capacity += str3Length;
        }

        if (str4 != null)
        {
            str4Length = str4.Length;
            capacity += str4Length;
        }

        if (str5 != null)
        {
            str5Length = str5.Length;
            capacity += str5Length;
        }

        if (str6 != null)
        {
            str6Length = str6.Length;
            capacity += str6Length;
        }

        if (str7 != null)
        {
            str7Length = str7.Length;
            capacity += str7Length;
        }


        string result = new string(' ', capacity);

        fixed (char* dest = result)
        {
            var x = dest;

            if (str1Length > 0)
            {
                fixed (char* src = str1)
                {
                    Unsafe.CopyBlock(x, src, (uint)str1Length * 2); 
                    x += str1Length;
                }
            }

            if (str2Length > 0)
            {
                fixed (char* src = str2)
                {
                    Unsafe.CopyBlock(x, src, (uint)str2Length * 2);
                    x += str2Length;
                }
            }

            if (str3Length > 0)
            {
                fixed (char* src = str3)
                {
                    Unsafe.CopyBlock(x, src, (uint)str3Length * 2);
                    x += str3Length;
                }
            }

            if (str4Length > 0)
            {
                fixed (char* src = str4)
                {
                    Unsafe.CopyBlock(x, src, (uint)str4Length * 2);
                    x += str4Length;
                }
            }

            if (str5Length > 0)
            {
                fixed (char* src = str5)
                {
                    Unsafe.CopyBlock(x, src, (uint)str5Length * 2);
                    x += str5Length;
                }
            }

            if (str6Length > 0)
            {
                fixed (char* src = str6)
                {
                    Unsafe.CopyBlock(x, src, (uint)str6Length * 2);
                    x += str6Length;
                }
            }

            if (str7Length > 0)
            {
                fixed (char* src = str7)
                {
                    Unsafe.CopyBlock(x, src, (uint)str7Length * 2);
                }
            }
        }

        return result;
    }

방법을 편집하여 상황에 맞게 조정할 수 있습니다.예를 들어 다음과 같이 만들 수 있습니다.

public static secure string FastConcat(string str1, str2, str3 = null, str4 = null, str5 = null, str6 = null, str7 = null)

단 2개의 문자열에 대해서는 String Builder를 사용하고 싶지 않습니다.String Builder 오버헤드가 여러 문자열을 할당하는 오버헤드보다 작은 임계값이 있습니다.

따라서 2-3개의 문자열에 대해서는 DannySmurf의 코드를 사용합니다.그렇지 않으면 + 연산자를 사용합니다.

사용 패턴에 따라 다릅니다.문자열 간의 상세 벤치마크.결합, 현악기, 콘캣, 현악기형식은 String에서 찾을 수 있습니다.포맷이 집약적인 로깅에 적합하지 않음

(실제로 이 질문에 대한 답변과 동일합니다)

암호에 따라 다르겠죠String Builder가 일반적으로 더 효율적이지만, 몇 개의 문자열을 연결하여 한 줄에 모두 실행하는 경우에는 코드 최적화를 통해 처리될 수 있습니다.코드가 어떻게 표시되는지 생각해 보는 것도 중요합니다.큰 세트의 경우 String Builder는 읽기 쉽고 작은 세트의 경우 String Builder는 불필요한 혼란을 가중시킵니다.

언급URL : https://stackoverflow.com/questions/21078/most-efficient-way-to-concatenate-strings

반응형