Skip to content

Conversation

@stephentoub
Copy link
Member

We can use a T's ISpanFormattable implementation to avoid the individual ToStrings. We also don't need to maintain a separate implementation for Concat; at the cost of one branch per value, we can just reuse the Join implementation and pick up all of its optimizations for Concat.

private IEnumerable<int> _intValues;
private IEnumerable<string> _stringValues;
private IEnumerable<object> _objectValues;

[GlobalSetup]
public void Setup()
{
    var r = new Random(42);
    _intValues = Enumerable.Range(0, 5).Select(_ => r.Next(int.MinValue, int.MaxValue)).ToList();
    _stringValues = _intValues.Select(i => i.ToString()).ToList();
    _objectValues = Enumerable.Range(0, 5).Select(i => new MyObj()).ToList();
}

[Benchmark] public string ConcatInt() => string.Concat(_intValues);
[Benchmark] public string ConcatString() => string.Concat<string>(_stringValues);
[Benchmark] public string JoinInt() => string.Join(", ", _intValues);
[Benchmark] public string JoinObject() => string.Join(", ", _objectValues);

private sealed class MyObj
{
    public override string ToString() => "Something";
}
Method Toolchain Mean Ratio Allocated Alloc Ratio
ConcatInt \main\corerun.exe 175.78 ns 1.00 408 B 1.00
ConcatInt \pr\corerun.exe 101.45 ns 0.58 168 B 0.41
ConcatString \main\corerun.exe 83.84 ns 1.00 168 B 1.00
ConcatString \pr\corerun.exe 51.36 ns 0.61 128 B 0.76
JoinInt \main\corerun.exe 141.82 ns 1.00 424 B 1.00
JoinInt \pr\corerun.exe 116.11 ns 0.82 184 B 0.43
JoinObject \main\corerun.exe 98.92 ns 1.00 168 B 1.00
JoinObject \pr\corerun.exe 99.97 ns 1.01 168 B 1.00

@ghost ghost added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label May 19, 2023
@ghost ghost assigned stephentoub May 19, 2023
@stephentoub stephentoub added area-System.Runtime and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels May 19, 2023
@ghost
Copy link

ghost commented May 19, 2023

Tagging subscribers to this area: @dotnet/area-system-runtime
See info in area-owners.md if you want to be subscribed.

Issue Details

We can use a T's ISpanFormattable implementation to avoid the individual ToStrings. We also don't need to maintain a separate implementation for Concat; at the cost of one branch per value, we can just reuse the Join implementation and pick up all of its optimizations for Concat.

private IEnumerable<int> _intValues;
private IEnumerable<string> _stringValues;
private IEnumerable<object> _objectValues;

[GlobalSetup]
public void Setup()
{
    var r = new Random(42);
    _intValues = Enumerable.Range(0, 5).Select(_ => r.Next(int.MinValue, int.MaxValue)).ToList();
    _stringValues = _intValues.Select(i => i.ToString()).ToList();
    _objectValues = Enumerable.Range(0, 5).Select(i => new MyObj()).ToList();
}

[Benchmark] public string ConcatInt() => string.Concat(_intValues);
[Benchmark] public string ConcatString() => string.Concat<string>(_stringValues);
[Benchmark] public string JoinInt() => string.Join(", ", _intValues);
[Benchmark] public string JoinObject() => string.Join(", ", _objectValues);

private sealed class MyObj
{
    public override string ToString() => "Something";
}
Method Toolchain Mean Ratio Allocated Alloc Ratio
ConcatInt \main\corerun.exe 175.78 ns 1.00 408 B 1.00
ConcatInt \pr\corerun.exe 101.45 ns 0.58 168 B 0.41
ConcatString \main\corerun.exe 83.84 ns 1.00 168 B 1.00
ConcatString \pr\corerun.exe 51.36 ns 0.61 128 B 0.76
JoinInt \main\corerun.exe 141.82 ns 1.00 424 B 1.00
JoinInt \pr\corerun.exe 116.11 ns 0.82 184 B 0.43
JoinObject \main\corerun.exe 98.92 ns 1.00 168 B 1.00
JoinObject \pr\corerun.exe 99.97 ns 1.01 168 B 1.00
Author: stephentoub
Assignees: stephentoub
Labels:

area-System.Runtime

Milestone: -

…Concat/Join(..., IEnumerable<T>)

We can use a T's ISpanFormattable implementation to avoid the individual ToStrings. We also don't need to maintain a separate implementation for Concat; at the cost of one branch per value, we can just reuse the Join implementation and pick up all of its optimizations for Concat.
@stephentoub stephentoub force-pushed the stringconcatjoinspan branch from d3255c1 to 28e66f8 Compare May 22, 2023 02:05
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants