为了评估 .NET9
平台上使用 C#
中不同字符串拼接操作的性能表现,我们可以使用 BenchmarkDotNet
这一强大的开源库来构建科学且可重复的基准测试。
BenchmarkDotNet
能够自动处理诸如 JIT 编译、预热(Warm-up)、运行次数控制、统计误差分析等底层细节,确保测试结果具有高度准确性与可比性。在 .NET9
中,使用 C#
字符串拼接的常见方式包括:
+
运算符string.Concat
string.Format
$"{variable}"
StringBuilder
为了满足大家对性能的需求,我会创建两个类:
StringConcatenationOperations.cs
:包含各种字符串拼接操作的实现。StringConcatenationBenchmark.cs
:使用 BenchmarkDotNet
对这些操作进行基准测试。以下是具体的代码实现。
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>ExeOutputType>
<TargetFramework>net9.0TargetFramework>
<ImplicitUsings>enableImplicitUsings>
<Nullable>enableNullable>
<PublishAot>truePublishAot>
<InvariantGlobalization>trueInvariantGlobalization>
PropertyGroup>
<ItemGroup>
<PackageReference Include="Datadog.Trace.BenchmarkDotNet" Version="2.61.0" />
ItemGroup>
Project>
StringConcatenationOperations
// ====================================================
// 字符串拼接实现:在 .NET 中,字符串拼接的常见方式
// ====================================================
using System.Text;
namespace BenchmarkTest.examples.StringConcatenation;
internal static class StringConcatenationOperations
{
// 使用 + 运算符
public static string UsePlusOperator(string a, string b, string c)
{
return a + b + c;
}
// 使用 string.Concat
public static string UseStringConcat(string a, string b, string c)
{
return string.Concat(a, b, c);
}
// 使用 string.Format
public static string UseStringFormat(string a, string b, string c)
{
return string.Format("{0}{1}{2}", a, b, c);
}
// 使用插值字符串 $"{variable}"
public static string UseStringInterpolation(string a, string b, string c)
{
return $"{a}{b}{c}";
}
// 使用 StringBuilder
public static string UseStringBuilder(string a, string b, string c)
{
var sb = new StringBuilder();
sb.Append(a);
sb.Append(b);
sb.Append(c);
return sb.ToString();
}
}
StringConcatenationBenchmark
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Running;
using Datadog.Trace.BenchmarkDotNet;
namespace BenchmarkTest.examples.StringConcatenation;
[DatadogDiagnoser]
[MemoryDiagnoser]
public class StringConcatenationBenchmark
{
private const string A = "Hello";
private const string B = " ";
private const string C = "World";
[Benchmark]
public string PlusOperator()
{
return StringConcatenationOperations.UsePlusOperator(A, B, C);
}
[Benchmark]
public string StringConcat()
{
return StringConcatenationOperations.UseStringConcat(A, B, C);
}
[Benchmark]
public string StringFormat()
{
return StringConcatenationOperations.UseStringFormat(A, B, C);
}
[Benchmark]
public string StringInterpolation()
{
return StringConcatenationOperations.UseStringInterpolation(A, B, C);
}
[Benchmark]
public string StringBuilder()
{
return StringConcatenationOperations.UseStringBuilder(A, B, C);
}
public static void Run(IConfig config)
{
var summary = BenchmarkRunner.Run<StringConcatenationBenchmark>(config);
Console.WriteLine(summary);
}
}
Program.cs
中运行基准测试using BenchmarkDotNet.Configs;
using Datadog.Trace.BenchmarkDotNet;
using BenchmarkTest.examples.StringConcatenation;
Console.WriteLine("Hello, BenchmarkDotNetTest!");
var config = DefaultConfig.Instance.WithDatadog();
StringConcatenationBenchmark.Run(config);
在项目根目录,使用 pwsh
终端输入命令:
dotnet run -c Release
输出信息:
以下是对 BenchmarkDotNet
测试结果的详细分析:
v0.13.2
Windows 11 (10.0.26100.4484)
9.0.301
.NET 9.0.6 (9.0.625.26613), X64 AOT AVX2
RyuJIT AVX2
方法名 | 平均耗时(Mean) | 误差范围(Error) | 标准差(StdDev) | GC Gen0 次数 | 内存分配 |
---|---|---|---|---|---|
PlusOperator | 21.01 ns | 0.233 ns | 0.207 ns | 0.0306 | 48 B |
StringConcat | 21.06 ns | 0.493 ns | 0.606 ns | 0.0306 | 48 B |
StringFormat | 78.65 ns | 1.389 ns | 1.300 ns | 0.0305 | 48 B |
StringInterpolation | 20.88 ns | 0.460 ns | 0.529 ns | 0.0306 | 48 B |
StringBuilder | 35.37 ns | 0.769 ns | 1.175 ns | 0.0969 | 152 B |
+
运算符拼接 (PlusOperator
)string.Concat
。string.Concat
(StringConcat
)+
相当。+
类似,但更推荐用于多参数拼接。string.Format
(StringFormat
)StringInterpolation
)C# 6
引入的新特性,语法简洁、可读性高。string.Format
或直接内联为 string.Concat
。StringBuilder
(StringBuilder
)StringBuilder
方法的执行时间分布呈现双峰(bimodal
),说明其性能波动较大。GC
影响、缓存命中率变化或其他外部因素。PlusOperator
、StringFormat
和 StringInterpolation
都检测到了一些性能异常值。GC
操作或其他临时干扰引起。使用场景 | 推荐方式 | 原因 |
---|---|---|
简单拼接 | + 或 string.Concat |
性能最佳,语法简洁 |
需要格式化输出 | string.Format |
功能强大,但性能略差 |
提高可读性和现代写法 | 插值字符串 $"{a}{b}" |
性能接近最优,语法清晰 |
循环拼接或大量拼接 | StringBuilder |
减少内存分配,避免频繁创建新字符串 |
高频调用的小规模拼接 | 避免使用 StringBuilder |
初始开销大,小规模拼接时不划算 |
如果你希望进一步优化测试,比如增加样本数量、调整测试参数,或者测试不同长度的字符串拼接,我可以帮助你修改基准测试代码。欢迎继续提问!