>我知道.net有一个叫做String.Join的函数,我可以把这个空格字符作为一个分隔符和原始的字符串一起传递给它.
>禁止使用String.Join,我可以使用StringBuilder类在每个字符之后追加空格.
>完成此任务的另一种方法是声明一个2 * n-1个字符的字符数组(您必须为空格添加n-1个字符).字符数组可以填充一个循环,然后传递给String构造函数.
我写了一些.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); }
更新:我已将项目更改为“发布”模式,并相应地更新了我的已用时间.
Why is using String.Join so much slower than doing the work by hand?
在这种情况下,String.Join较慢的原因是您可以编写一个先前知道您的IEnumerable< T>的确切性质的算法.
另一方面,String.Join<T>(string,IEnumerable<T>)
(您正在使用的超载)旨在与任何可任意枚举类型一起使用,这意味着它不能预分配到适当的大小.在这种情况下,它的纯粹的性能和速度具有灵活性.
许多框架方法都可以处理某些情况,通过检查条件可以加快事情的进行,但这通常只有在“特殊情况”将是常见的情况下才能实现.
在这种情况下,您正在有效地创建一个手写例程更快的边缘情况,但它不是String.Join的常见用例.在这种情况下,由于您确切地提前知道所需要的内容,因此您可以通过预先分配正确大小的数组并手动构建结果来避免灵活设计所需的所有开销.
您会发现,一般来说,通常可能会编写一种方法,该方法将为特定输入数据执行一些框架例程.这是常见的,因为框架例程必须与任何数据集一起使用,这意味着您无法针对特定输入方案进行优化.