julian bechtold
julian bechtold

Reputation: 2251

Performance optimizing looped string concatenations in c#

I have an application which processes some historical data. I did some performance profiling and identified the following function as the new Bottleneck:

public string GenerateSaveStringOptimized()
{
    StringBuilder saveString = new StringBuilder();
    saveString.Append( $"{this.TimeOfDay},{this.DayOfMonth},{this.DayOfYear},");
    foreach (float value in this.MovingAverage3h) saveString.Append($"{value},");
    foreach (float value in this.MovingAverage6h) saveString.Append($"{value},");
    foreach (float value in this.MovingAverage1d) saveString.Append($"{value},");
    foreach (float value in this.MovingAverage6d) saveString.Append($"{value},");
    foreach (float value in this.MovingAverage12d) saveString.Append($"{value},");
    foreach (float value in this.MovingAverage24d) saveString.Append($"{value},");
    foreach (float value in this.MovingAverage48d) saveString.Append($"{value},");
    foreach (float value in this.MovingAverage96d) saveString.Append($"{value},");
    foreach (float value in this.RSI3h) saveString.Append($"{value},");
    foreach (float value in this.RSI6h) saveString.Append($"{value},");
    foreach (float value in this.RSI1d) saveString.Append($"{value},");
    foreach (float value in this.RSI6d) saveString.Append($"{value},");
    foreach (float value in this.RSI12d) saveString.Append($"{value},");
    foreach (float value in this.Momentum1h) saveString.Append($"{value},");
    foreach (float value in this.SpotPrices1h) saveString.Append($"{value},");
    foreach (float value in this.BuyPrices1h) saveString.Append($"{value},");
    foreach (float value in this.SellPrices1h) saveString.Append($"{value},");
    saveString.Append($"{this.Label}");
    return saveString.ToString();
}

enter image description here

The Result will be a string in csv format such as:

0,1,1,0.4916667,0.4916667,0.4916667,0.4916667,0.4916667,0.49,0.49,0.49,0.49,0.4897351, [...]

Each of those arrays contains 25 float values so the code is similar to the following pseudocode:

for (int i = 0; i < 17; i++)
{
    for (b = 0; b < 25 b++)
    {
        saveString.Append("Value,")
    }
}

that makes 17 * 25 = 425 string concatenations for each call of that function!

Is there a way I can optimize it?

The Top performance eater seems to be "waiting for cpu" and "AppendformatHelper" which is a builtin Method from StringBuilder. Unfortunately not something where I know how to treat that easily
enter image description here

Maybe with a Hardcoded Setup as the following?

saveString.Append($"{MA3h[0]},{MA3h[1]},{MA3h[2]},...");
saveString.Append($"{MA6h[0]},{MA6h[1]},{MA6h[2]},...");
saveString.Append($"{MA1d[0]},{MA1d[1]},{MA1d[2]},...");

A great Success was made by using the following loops instead:

foreach (float value in this.RSI1d)
{
    saveString.Append(value.ToString());
    saveString.Append(',');
}

A very Big thank you to user1672994, Guru Stron and Theodor Zoulias

The other mentions in the comments will be tried as well.

Upvotes: 4

Views: 838

Answers (1)

Alexander Petrov
Alexander Petrov

Reputation: 14231

Preallocate a sufficient amount of capacity.

StringBuilder saveString = new StringBuilder(100000);

Don't use formatting or interpolation.

saveString.Append(this.TimeOfDay).Append(',').Append(this.DayOfMonth).Append(',').Append(this.DayOfYear).Append(',');

Perform similar substitutions in all loops.

foreach (float value in this.MovingAverage3h) saveString.Append(value).Append(',');

Don't use formatting or interpolation.

saveString.Append(this.Label);

The Append method has an overload that accepts float, so there will be no boxing.

Upvotes: 4

Related Questions