Reputation: 2251
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();
}
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
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
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