Skip to content

Instantly share code, notes, and snippets.

@davepcallan
Last active February 15, 2025 22:50
Show Gist options
  • Save davepcallan/2063c516d6ea377e6c161bbc39c58701 to your computer and use it in GitHub Desktop.
Save davepcallan/2063c516d6ea377e6c161bbc39c58701 to your computer and use it in GitHub Desktop.
.NET 8 simple string concatenation benchmarks
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Columns;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Jobs;
using BenchmarkDotNet.Reports;
using System;
using System.Text;
namespace Benchmarks
{
[MemoryDiagnoser]
[Config(typeof(Config))]
[SimpleJob(RuntimeMoniker.Net80)]
[HideColumns(Column.Job, Column.RatioSD, Column.AllocRatio)]
public class StringConcatSimple
{
private class Config : ManualConfig
{
public Config()
{
SummaryStyle =
SummaryStyle.Default.WithRatioStyle(RatioStyle.Percentage);
}
}
private string
title = "Mr.", firstName = "David", middleName = "Patrick", lastName = "Callan";
[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 });
}
[Benchmark(Baseline = true)]
public string StringCreate()
{
return String.Create(title.Length + firstName.Length + middleName.Length + lastName.Length + 3,
(title, firstName, middleName, lastName),
(span, state) =>
{
state.title.AsSpan().CopyTo(span);
span = span.Slice(state.title.Length);
span[0] = ' ';
span = span.Slice(1);
state.firstName.AsSpan().CopyTo(span);
span = span.Slice(state.firstName.Length);
span[0] = ' ';
span = span.Slice(1);
state.middleName.AsSpan().CopyTo(span);
span = span.Slice(state.middleName.Length);
span[0] = ' ';
span = span.Slice(1);
state.lastName.AsSpan().CopyTo(span);
}
);
}
}
}
@davidfowl
Copy link

You can also do string interpolation with the last example using TryWrite:

class MyClass
{
    private string
           title = "Mr.", firstName = "David", middleName = "Patrick", lastName = "Callan";

    public string StringCreate()
    {
        return string.Create(title.Length + firstName.Length + middleName.Length + lastName.Length + 3,
            (title, firstName, middleName, lastName),
            (span, state) => span.TryWrite($"{state.title} {state.firstName} {state.middleName} {state.lastName}", out _));
    }
}

@davepcallan
Copy link
Author

Thanks David, I had no idea you could do this, it's a lot cleaner.
Very helpful thank you.

@dsidirop
Copy link

@davepcallan Appreciate the awesome tests-suite here and the benchmarks. Quick question off of the top of my head (might be suggesting something wacky - bear with me):

Would it be possible and would it help at all in terms of performance to get the bytes in the callback of String.Create() as UTF8?

Thanks again!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment