[C# 문법] C# StringBuilder 성능 개선
- C#/C# 문법
- 2022. 4. 28. 21:28
참조
- https://andrewlock.net/a-deep-dive-on-stringbuilder-part-5-reducing-allocations-by-caching-stringbuilders-with-stringbuildercache/
- https://www.meziantou.net/stringbuilder-performance-pitfalls.htm
목적
- 회사에서 특정 라이브러리 성능 개선을 하던 중, 특정 코드에 유독 StringBuilder 클래스를 자주 사용하는 것을 보게 되었습니다.
- StringBuilder 를 보다 빠르게 사용하는? 방법이 없을까 인터넷을 찾던 중,
StringBuilderCache
클래스를 사용하면 성능적으로 더 빨라진다고 하여 실제로 그러한지 벤치마크를 통해 알아 보았습니다.
개발 환경
- IDE : Visual Studio 2022
- .NET Version : .NET 6
StringBuilderCache.cs
- 참고로,
StringBuilderCache.cs
는 C# 에서 따로 클래스를 추가해서 사용해야 합니다. - .NET 자체의 Internal 클래스로써, 일반적으로 using 구문을 통해서는 사용하지 못합니다.
- 때문에 저는 micfosoft git 사이트에서
StringBuilderCache.cs
클래스를 똑같이 구현하여 테스트 진행 하였습니다.
StringBuilderCache.cs
- StringBuilderCache 클래스 내용은 다음과 같습니다.
using System.Threading;
namespace System.Text
{
internal static class StringBuilderCache
{
// The value 360 was chosen in discussion with performance experts as a compromise between using
// as litle memory (per thread) as possible and still covering a large part of short-lived
// StringBuilder creations on the startup path of VS designers.
private const int MAX_BUILDER_SIZE = 360;
[ThreadStatic]
private static StringBuilder CachedInstance;
public static StringBuilder Acquire(int capacity = StringBuilder.DefaultCapacity)
{
if(capacity <= MAX_BUILDER_SIZE)
{
StringBuilder sb = StringBuilderCache.CachedInstance;
if (sb != null)
{
// Avoid stringbuilder block fragmentation by getting a new StringBuilder
// when the requested size is larger than the current capacity
if(capacity <= sb.Capacity)
{
StringBuilderCache.CachedInstance = null;
sb.Clear();
return sb;
}
}
}
return new StringBuilder(capacity);
}
public static void Release(StringBuilder sb)
{
if (sb.Capacity <= MAX_BUILDER_SIZE)
{
StringBuilderCache.CachedInstance = sb;
}
}
public static string GetStringAndRelease(StringBuilder sb)
{
string result = sb.ToString();
Release(sb);
return result;
}
}
}
벤치마크 코드
- 벤치 마크 코드는 다음과 같습니다.
- 벤치마크는 참고로
BenchMarkDotNet
NuGet Package 를 설치하여 사용하였습니다. - StringBuilder, StringBuilderCache 2개의 클래스를 비교하는 메서드를 생성하였고, 반복문은 각각 10번, 100번, 1000번, 2000번, 10000번, 100000번, 1000000번 테스트 진행 하였습니다.
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using System.Text;
var summary = BenchmarkRunner.Run<BenchMarkTest>();
[MemoryDiagnoser]
public class BenchMarkTest
{
[Params(10, 100, 1000, 2000, 10000, 100000, 1000000)]
public int Count { get; set; }
[Benchmark]
public void AppendStringUsingStringBuilder()
{
for(int index = 0; index < Count; index++)
{
var stringBuilder = new StringBuilder();
stringBuilder.Append("First String");
stringBuilder.Append("Second String");
stringBuilder.Append("Third String");
string value = stringBuilder.ToString();
}
}
[Benchmark]
public void AppendStringUsingStringBuilderCache()
{
StaticClass.AppendStringUsingStringBuilderCache(Count);
}
}
public static class StaticClass
{
[Benchmark]
public static void AppendStringUsingStringBuilderCache(int Count)
{
for (int index = 0; index < Count; index++)
{
StringBuilder stringBuilder = StringBuilderCache.Acquire();
stringBuilder.Append("First String");
stringBuilder.Append("Second String");
stringBuilder.Append("Third String");
string value = StringBuilderCache.GetStringAndRelease(stringBuilder);
}
}
}
실행 결과
- 벤치마크 실행 결과, StringBuilder 보다 StringBuilderCahce 클래스를 사용했을 때 속도가 2배이상 줄어든 것을 확인할 수 있습니다.
728x90
'C# > C# 문법' 카테고리의 다른 글
[C# 동시성 프로그래밍] - 일정 시간 동안 일시 정지 (0) | 2022.05.08 |
---|---|
[C# 동시성 프로그래밍] - 동시성 프로그래밍 개념 정리 (0) | 2022.05.07 |
[C# 문법] .NET 콘솔 서비스 - DockerFile, Imgae, Containger 생성하기 (0) | 2022.03.18 |
[C# 문법] C# 에서 Process로 Python 파일 실행하기 (0) | 2022.03.18 |
[C# 문법] C# 에서 IronPython 이용하여 Python 연동 (0) | 2022.03.18 |
이 글을 공유하기