Dan*_*don 13 .net c# string string-concatenation
我一直在研究一个呈现给我的问题:如何编写一个函数,该函数将字符串作为输入并返回字符之间带有空格的字符串.编写该函数是为了在每秒调用数千次时优化性能.
我知道.net有一个调用的函数String.Join,我可以将空格字符作为分隔符和原始字符串一起传递给它.
除非使用String.Join,我可以使用StringBuilder该类在每个字符后追加空格.
完成此任务的另一种方法是声明一个包含2*n-1个字符的字符数组(您必须为空格添加n-1个字符).字符数组可以在循环中填充,然后传递给String constructor.
我编写了一些.net代码,每个算法使用参数运行每个算法一百万次,"Hello, World"并测量执行所需的时间.方法(3)比(1)或(2)快得多.
我知道(3)应该非常快,因为它避免创建任何额外的字符串引用被垃圾收集,但在我看来,内置的.net函数String.Join应该会产生良好的性能.为什么使用String.Join比手工工作慢得多?
public static class TestClass
{
// 491 milliseconds for 1 million iterations
public static string Space1(string s)
{
return string.Join(" ", s.AsEnumerable());
}
//190 milliseconds for 1 million iterations
public static string Space2(string s)
{
if (s.Length < 2)
return s;
StringBuilder sb = new StringBuilder();
sb.Append(s[0]);
for (int i = 1; i < s.Length; i++)
{
sb.Append(' ');
sb.Append(s[i]);
}
return sb.ToString();
}
// 50 milliseconds for 1 million iterations
public static string Space3(string s)
{
if (s.Length < 2)
return s;
char[] array = new char[s.Length * 2 - 1];
array[0] = s[0];
for (int i = 1; i < s.Length; i++)
{
array[2*i-1] = ' ';
array[2*i] = s[i];
}
return new string(array);
}
Run Code Online (Sandbox Code Playgroud)
更新:我已将项目更改为"发布"模式并相应地更新了问题中的已用时间.
为什么使用String.Join要比手工工作慢得多?
在这种情况下,原因String.Join是速度较慢,您可以编写一个先前已知您的确切性质的算法.IEnumerable<T>
String.Join<T>(string, IEnumerable<T>)(另一方面,您正在使用的重载)旨在使用任何可任意的可枚举类型,这意味着它无法预先分配到适当的大小.在这种情况下,它具有纯粹的性能和速度的交易灵活性.
许多框架方法确实处理某些情况,通过检查条件可以加速事情,但这通常只在"特殊情况"变得普遍时才会完成.
在这种情况下,您正在有效地创建一个边缘情况,其中手写例程将更快,但它不是常见的用例String.Join.在这种情况下,由于您事先确切地知道所需的内容,因此您可以通过预先分配大小合适的数组并手动构建结果来避免设置灵活所需的所有开销.
您会发现,通常情况下,通常可以编写一个方法来执行某些特定输入数据的框架例程.这很常见,因为框架例程必须与任何数据集一起使用,这意味着您无法针对特定输入方案进行优化.