前段时间我有一个案例,即使用MyString.Skip(..).Take(..)
代替MyString.Substring(..)
很方便。但是Skip
和Take
会返回IEnumerable<char>
而不是新的string
,所以我编写了自己的concat函数:
public static string Concat(this IEnumerable<char> char_sequence) {
var sb = new StringBuilder();
foreach (var c in char_sequence)
{
sb.Append(c);
}
return sb.ToString();
}
今天我不得不做同样的事情,但记得改为使用Aggregate
:
MyString.Skip(..).Take(..).Aggregate(new StringBuilder(), (current, next) => current.Append(next)).ToString()
因为代码已经存在,所以我进行了快速的性能测试。对于大型文本文件,Aggregate
似乎要慢50%以上:
480KB .txt document, 1000 iterations (loading the document was not included in the test)
Function | Time (ms)
--------------------
Aggregate| 14,701
Concat | 8,068
但为什么呢?根据{{3}},Aggregate
使用此方法:
public static TAccumulate Aggregate<TSource, TAccumulate>(this IEnumerable<TSource> source, TAccumulate seed, Func<TAccumulate, TSource, TAccumulate> func) {
if (source == null) throw Error.ArgumentNull("source");
if (func == null) throw Error.ArgumentNull("func");
TAccumulate result = seed;
foreach (TSource element in source) result = func(result, element);
return result;
}
如果您将TSource
替换为char
而TAccumulate
替换为StringBuilder
,则代码基本相同。这种速度差异来自哪里,有没有办法加快Aggregate
?
为了完整起见,在我写这个问题之前,我实际上做了两个以上的基准测试(虽然我因某种原因忘记了Substring
,所以我不得不再次运行它)。请记住,我的问题不是关于使用什么,而是为什么Aggregate
和自定义Concat
之间存在差异。
Function | Time (ms) (Additional Notes)
-----------------------------------------------------------
Aggregate | 14070
Parallel().Aggregate | 14016 (uses only one thread)
new String() | 7784
String.Concat | 13342
Concat Extension | 7997
Substring | 329