programing

문자열 보간 대 문자열.서식

muds 2023. 9. 28. 08:51
반응형

문자열 보간 대 문자열.서식

문자열 보간을 사용하는 것 사이에 현저한 성능 차이가 있습니까?

myString += $"{x:x2}";

vs 문자열.형식()?

myString += String.Format("{0:x2}", x);

ReSharper가 수정을 요청하고 있고, 전에 속아본 적이 있기 때문에 묻는 것입니다.

주목할 만한 것은 상대적인 것입니다.나:.string.Format()컴파일 타임에 그들은 결국 같은 결과로 끝나야 합니다.

하지만 미묘한 차이가 있습니다. 이 질문에서 알 수 있듯이 형식 지정자의 문자열 연결은 추가적인 결과를 가져옵니다.string.Concat()러.

대답은 '그렇다'와 '아니오' 둘 다 입니다.ReSharper 가장 성능이 뛰어난 세 번째 변형을 보여주지 않음으로써 여러분을 속이는 입니다.나열된 두 가지 변형은 동일한 IL 코드를 생성하지만, 다음과 같은 것이 실제로 강화됩니다.

myString += $"{x.ToString("x2")}";

전체테스트코드

using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Diagnosers;
using BenchmarkDotNet.Diagnostics.Windows;
using BenchmarkDotNet.Running;

namespace StringFormatPerformanceTest
{
    [Config(typeof(Config))]
    public class StringTests
    {
        private class Config : ManualConfig
        {
            public Config() => AddDiagnoser(MemoryDiagnoser.Default, new EtwProfiler());
        }

        [Params(42, 1337)]
        public int Data;

        [Benchmark] public string Format() => string.Format("{0:x2}", Data);
        [Benchmark] public string Interpolate() => $"{Data:x2}";
        [Benchmark] public string InterpolateExplicit() => $"{Data.ToString("x2")}";
    }

    class Program
    {
        static void Main(string[] args)
        {
            var summary = BenchmarkRunner.Run<StringTests>();
        }
    }
}

시험결과

|              Method | Data |      Mean |  Gen 0 | Allocated |
|-------------------- |----- |----------:|-------:|----------:|
|              Format |   42 | 118.03 ns | 0.0178 |      56 B |
|         Interpolate |   42 | 118.36 ns | 0.0178 |      56 B |
| InterpolateExplicit |   42 |  37.01 ns | 0.0102 |      32 B |
|              Format | 1337 | 117.46 ns | 0.0176 |      56 B |
|         Interpolate | 1337 | 113.86 ns | 0.0178 |      56 B |
| InterpolateExplicit | 1337 |  38.73 ns | 0.0102 |      32 B |

신규시험결과(.)NET 6)

테스트를 다시 실행합니다..NET 6.0.9.41905, X64 RyuJIT AVX2.

|              Method | Data |      Mean |   Gen0 | Allocated |
|-------------------- |----- |----------:|-------:|----------:|
|              Format |   42 |  37.47 ns | 0.0089 |      56 B |
|         Interpolate |   42 |  57.61 ns | 0.0050 |      32 B |
| InterpolateExplicit |   42 |  11.46 ns | 0.0051 |      32 B |
|              Format | 1337 |  39.49 ns | 0.0089 |      56 B |
|         Interpolate | 1337 |  59.98 ns | 0.0050 |      32 B |
| InterpolateExplicit | 1337 |  12.85 ns | 0.0051 |      32 B |

InterpolateExplicit()다가 더 빠릅니다.string. 포맷할 개체박스에 넣을 필요가 없습니다.복싱은 정말 돈이 많이 듭니다.참고할 점은NET 6모든 방법에 대해 CPU 및 메모리 할당을 모두 줄였습니다.

신규시험결과(.)NET 7)

테스트를 다시 실행합니다..NET 7.0.122.56804, X64 RyuJIT AVX2.

|              Method | Data |      Mean |   Gen0 | Allocated |
|-------------------- |----- |----------:|-------:|----------:|
|              Format |   42 |  41.04 ns | 0.0089 |      56 B |
|         Interpolate |   42 |  65.82 ns | 0.0050 |      32 B |
| InterpolateExplicit |   42 |  12.19 ns | 0.0051 |      32 B |
|              Format | 1337 |  41.02 ns | 0.0089 |      56 B |
|         Interpolate | 1337 |  59.61 ns | 0.0050 |      32 B |
| InterpolateExplicit | 1337 |  13.28 ns | 0.0051 |      32 B |

이후 큰 ..NET 6.

C#10 및 에서 문자열 보간에 대한 상당한 최적화가 있었음을 유의해야 합니다.NET 6 - C# 10.의 문자열 보간.NET 6.

저는 문자열 형식뿐만 아니라 문자열 연결의 모든 용도를 문자열 보간을 사용하기 위해 마이그레이션해 왔습니다.

저는 다른 방법들 간의 메모리 할당 차이에 대해 더 관심을 가질 것입니다.문자열 인터폴레이션은 적은 수의 문자열로 작업할 때 속도와 메모리 할당 모두에서 거의 항상 유리하다는 것을 발견했습니다.지정되지 시 알 수 경우 은는)다를 System.Text.StringBuilder.Append(xxx)아니면System.Text.StringBuilder.AppendFormat(xxx)

당신의 .+=문자열 연결에 사용할 수 있습니다.매우 조심하고 적은 수의 줄에 대해서만 주의해야 합니다.

그 문제는 성능에 관한 것이었는데 제목에 "vs"라고만 쓰여 있어서 몇 점을 더 추가해야 할 것 같아요, 그 중 일부는 의견이 있습니다.

  • 현지화

    • 문자열 보간은 인라인 코드 특성 때문에 지역화할 수 없습니다.에다로 .string.Format (:ReSharper).
  • 유지가능성(나의 의견)

    • string.Format문장에 초점을 맞추기 때문에 훨씬 더 가독성이 높습니다. 예를 들어, 멋지고 의미 있는 오류 메시지를 작성할 때 말입니다.사용.{N}자리 표시자는 제게 더 많은 유연성을 주고 나중에 수정하는 것이 더 쉽습니다.
    • 또한 보간에서 인라인 형식 지정자는 잘못 읽히기 쉽고, 변경 시 식과 함께 삭제하기 쉽습니다.
    • 복잡하고 긴 표현을 사용하는 경우 보간은 읽기와 유지가 더 어려워지기 때문에 코드가 진화하고 복잡해질 때 확장이 잘 되지 않습니다.string.Format이런 일이 일어나기 쉬운 건 아닙니다
    • 결국, 모든 것은 우려의 분리에 관한 것입니다.저는 그것이 제시해야 할 내용과 제시해야 내용을 혼합하는 것을 좋아하지 않습니다.

그래서 이것들을 바탕으로, 저는 계속하기로 결정했습니다.string.Format대부분의 내 암호대로라면하지만 제가 훨씬 더 좋아하는 코딩을 좀 더 유창하게 하기 위해 확장 방법을 준비했습니다.확장의 구현은 원-라이너이며, 단순히 사용 중인 것처럼 보입니다.

var myErrorMessage = "Value must be less than {0:0.00} for field {1}".FormatWith(maximum, fieldName);

인터폴레이션은 훌륭한 기능입니다. 오해하지 마세요.다 IMO라는 빛납니다.string.Format예를 들어 자바스크립트와 같은 기능입니다.

이 .string.Format()컴파일 타임에

string.Format()에 대해 할 수 있고, 출력 형식을 할 수 있습니다 .

하지만 문자열 보간이 더 읽기 쉬운 것 같습니다.그러니까, 당신한테 달렸어요.

a = string.Format("Due date is {0:M/d/yy} at {0:h:mm}", someComplexObject.someObject.someProperty);

b = $"Due date is {someComplexObject.someObject.someProperty:M/d/yy} at {someComplexObject.someObject.someProperty:h:mm}";

사용 가능한 성능 테스트 결과는 다음과 같습니다.

https://koukia.ca/string-interpolation-vs-string-format-string-concat-and-string-builder-performance-benchmarks-c1dad38032a

늦었을 도 있지만 한 것을하지 못했습니다. 가 것을 . 나는 그것을 알아차렸습니다.+=당신의 질문에 연산자가 있습니다.이 작업을 주기적으로 실행하는 것의 16진수 출력을 생성하는 것 같습니다.

)+=할 수 ), .OutOfMemoryException쓰레기장을 분석하는 동안 안에 수많은 여유 메모리가 있을 것입니다!

어떻게 되는 거지?

  1. 메모리 관리자는 결과 문자열을 저장할 수 있는 충분한 연속 공간을 찾습니다.
  2. 연결된 문자열이 적혀 있습니다.
  3. 원래 왼쪽 변수의 값을 저장하는 데 사용되는 공간입니다.

1단계에서 할당된 공간은 3단계에서 해방된 공간보다 확실히 더 큽니다.

다음 사이클에서도 동일한 현상이 발생합니다.각 주기마다 10바이트 길이의 문자열이 원래 20바이트 길이의 문자열에 3번 추가되었다고 가정하면 우리의 메모리는 어떻게 보일까요?

[20바이트 사용 가능]X1[30바이트 사용 가능]X2[40바이트 사용 가능]X2[50바이트 할당됨]

(왜냐하면 사이클 중에 메모리를 사용하는 다른 명령어들이 있을 것이 거의 확실하기 때문입니다. 저는 메모리 할당을 설명하기 위해 Xn-s를 배치했습니다.이것들은 자유로워질 수도 있고 여전히 할당될 수도 있습니다. 저를 따라오세요.)

다음 할당 시 MM에서 충분한 크기의 연속 메모리(60바이트)가 발견되지 않으면 OS에서 가져오거나 콘센트의 여유 공간을 재구성하여 가져오려고 합니다.X1과 X2는 (가능한 경우) 어딘가로 이동될 것이고 20+30+40 연속 블록이 사용 가능하게 될 것입니다.시간이 걸리지만 사용 가능합니다.

그러나 블록 크기가 88kb(google for it why 88kb)에 도달하면 Large Object Heap에 할당됩니다.이곳의 무료 블록은 더 이상 압축되지 않습니다.

따라서 문자열 += 연산 결과가 이 크기를 초과하는 경우(예: CSV 파일을 구축하거나 메모리에 무엇인가를 이런 식으로 렌더링하는 경우), 위 사이클을 통해 계속해서 크기가 증가하는 빈 메모리 덩어리가 생성되고, 그 합계는 기가바이트가 될 수 있습니다.하지만 앱이 1Mb 정도의 작은 블록을 할당할 수 없기 때문에 앱이 OOM으로 종료됩니다. 왜냐하면 어떤 청크도 충분히 크지 않기 때문입니다.

긴 설명 죄송합니다만, 몇 년 전에 일어난 일이라 힘든 교훈이었습니다.저는 그 이후로 스트링 콘캣의 부적절한 사용에 맞서 싸우고 있습니다.

에 대한 .String.Format()마이크로소프트 사이트에서 다음을 확인할 수 있습니다.

https://learn.microsoft.com/en-us/dotnet/api/system.string.format?view=net-6.0#remarks

String을 부르는 대신에.형식 방법 또는 복합 형식 문자열을 사용하여 언어가 지원하는 경우 보간 문자열을 사용할 수 있습니다.보간 문자열은 보간된 식을 포함하는 문자열입니다.보간된 각 식은 식의 값으로 해결되며 문자열이 할당되면 결과 문자열에 포함됩니다.

언급URL : https://stackoverflow.com/questions/32342392/string-interpolation-vs-string-format

반응형