.NET9 实现字符串拼接(StringConcatenation)性能测试

发布于:2025-07-08 ⋅ 阅读:(16) ⋅ 点赞:(0)

为了评估 .NET9 平台上使用 C# 中不同字符串拼接操作的性能表现,我们可以使用 BenchmarkDotNet 这一强大的开源库来构建科学且可重复的基准测试。

  • BenchmarkDotNet 能够自动处理诸如 JIT 编译、预热(Warm-up)、运行次数控制、统计误差分析等底层细节,确保测试结果具有高度准确性与可比性。

.NET9 中,使用 C# 字符串拼接的常见方式包括:

  1. 使用 + 运算符
  2. 使用 string.Concat
  3. 使用 string.Format
  4. 使用插值字符串 $"{variable}"
  5. 使用 StringBuilder

为了满足大家对性能的需求,我会创建两个类:

  • StringConcatenationOperations.cs:包含各种字符串拼接操作的实现。
  • StringConcatenationBenchmark.cs:使用 BenchmarkDotNet 对这些操作进行基准测试。

以下是具体的代码实现。


项目准备

  • 项目信息
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net9.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <PublishAot>true</PublishAot>
    <InvariantGlobalization>true</InvariantGlobalization>
  </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

输出信息:

StringConcatenationBenchmark

以下是对 BenchmarkDotNet 测试结果的详细分析:


🧪 测试环境信息

  • BenchmarkDotNet 版本: v0.13.2
  • 操作系统: Windows 11 (10.0.26100.4484)
  • .NET SDK: 9.0.301
  • 运行时: .NET 9.0.6 (9.0.625.26613), X64 AOT AVX2
  • JIT 编译器: 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

🔍 逐项分析

1. + 运算符拼接 (PlusOperator)
  • 平均耗时: 21.01 ns
  • 内存分配: 48 字节
  • 特点:
    • 简洁直观,适合少量字符串拼接。
    • 在编译时会自动优化为 string.Concat
  • 结论: 性能优秀,适合简单拼接场景。
2. string.Concat (StringConcat)
  • 平均耗时: 21.06 ns
  • 内存分配: 48 字节
  • 特点:
    • 直接调用底层方法,性能与 + 相当。
    • 更加显式地表达意图,适合对性能敏感或需要明确控制拼接逻辑的代码。
  • 结论: 和 + 类似,但更推荐用于多参数拼接。
3. string.Format (StringFormat)
  • 平均耗时: 78.65 ns
  • 内存分配: 48 字节
  • 特点:
    • 支持格式化字符串,适合需要插入变量和格式控制的场景。
    • 由于涉及解析格式字符串,性能较差。
  • 结论: 如果需要格式化,可以使用;否则建议避免。
4. 插值字符串 (StringInterpolation)
  • 平均耗时: 20.88 ns
  • 内存分配: 48 字节
  • 特点:
    • C# 6 引入的新特性,语法简洁、可读性高。
    • 实际上会被编译为 string.Format 或直接内联为 string.Concat
  • 结论: 性能优异,同时具备良好的可读性,推荐使用。
5. StringBuilder (StringBuilder)
  • 平均耗时: 35.37 ns
  • 内存分配: 152 字节
  • 特点:
    • 适用于频繁修改或大量拼接的场景(如循环中拼接字符串)。
    • 初始化和操作有一定开销,不适合一次性小规模拼接。
  • 结论: 多次拼接时优势明显,单次拼接不推荐。

⚠️ 警告信息

  • MultimodalDistribution(多峰分布)
    • StringBuilder 方法的执行时间分布呈现双峰(bimodal),说明其性能波动较大。
    • 可能原因:GC 影响、缓存命中率变化或其他外部因素。

⚠️ 提示信息

  • Outliers(异常值)
    • PlusOperatorStringFormatStringInterpolation 都检测到了一些性能异常值。
    • 通常由系统负载、GC 操作或其他临时干扰引起。
    • 建议多次运行以确保数据稳定性。

📌 总结建议

使用场景 推荐方式 原因
简单拼接 +string.Concat 性能最佳,语法简洁
需要格式化输出 string.Format 功能强大,但性能略差
提高可读性和现代写法 插值字符串 $"{a}{b}" 性能接近最优,语法清晰
循环拼接或大量拼接 StringBuilder 减少内存分配,避免频繁创建新字符串
高频调用的小规模拼接 避免使用 StringBuilder 初始开销大,小规模拼接时不划算

如果你希望进一步优化测试,比如增加样本数量、调整测试参数,或者测试不同长度的字符串拼接,我可以帮助你修改基准测试代码。欢迎继续提问!


网站公告

今日签到

点亮在社区的每一天
去签到